No menu items!
No menu items!
More

    [Flask] – Phần 10: Tạo Database với SQLAlchemy sử dụng MySQL

    Bài trước chúng ta đã tìm hiểu SQLAlchemy là gì và thực hành nó với SQLite, bài này chúng ta hãy thử thực hành tạo Database trên MySQL bằng SQLAlchemy nhé.

    Để cài đặt được module mysqlclient cho Python, bạn cần cài đặt các gói tin cần thiết sau:

    sudo apt-get update
    sudo apt-get install gcc libmysqlclient-dev python3-dev -y 
    sudo apt install pkg-config -y 

    Vào trong môi trường ảo bạn hãy cài đặt SQLAlchemy bằng lệnh pip install sqlalchemy.

    $ pip install Flask-SQLAlchemy
    Collecting sqlalchemy
      Downloading SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.0 MB)
         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.0/3.0 MB 11.9 MB/s eta 0:00:00
    Collecting greenlet!=0.4.17
      Downloading greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (613 kB)
         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 613.7/613.7 KB 23.2 MB/s eta 0:00:00
    Collecting typing-extensions>=4.2.0
      Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB)
    Installing collected packages: typing-extensions, greenlet, sqlalchemy
    Successfully installed greenlet-2.0.2 sqlalchemy-2.0.20 typing-extensions-4.7.1

    Tiếp tục cài đặt module mysqlclient.

    $ pip install mysqlclient
    Collecting mysqlclient
      Using cached mysqlclient-2.2.0.tar.gz (89 kB)
      Installing build dependencies ... done
      Getting requirements to build wheel ... done
      Installing backend dependencies ... done
      Preparing metadata (pyproject.toml) ... done
    Requirement already satisfied: flask>=2.2.5 in /home/myproject/.venv/lib/python3.10/site-packages (from Flask-SQLAlchemy->-r requirements.txt (line 1)) (2.3.3)
    Requirement already satisfied: sqlalchemy>=1.4.18 in /home/myproject/.venv/lib/python3.10/site-packages (from Flask-SQLAlchemy->-r requirements.txt (line 1)) (2.0.20)
    Requirement already satisfied: bcrypt>=3.1.1 in /home/myproject/.venv/lib/python3.10/site-packages (from Flask-Bcrypt->-r requirements.txt (line 2)) (4.0.1)
    Requirement already satisfied: blinker>=1.6.2 in /home/myproject/.venv/lib/python3.10/site-packages (from flask>=2.2.5->Flask-SQLAlchemy->-r requirements.txt (line 1)) (1.6.2)
    Requirement already satisfied: itsdangerous>=2.1.2 in /home/myproject/.venv/lib/python3.10/site-packages (from flask>=2.2.5->Flask-SQLAlchemy->-r requirements.txt (line 1)) (2.1.2)
    Requirement already satisfied: Werkzeug>=2.3.7 in /home/myproject/.venv/lib/python3.10/site-packages (from flask>=2.2.5->Flask-SQLAlchemy->-r requirements.txt (line 1)) (2.3.7)
    Requirement already satisfied: click>=8.1.3 in /home/myproject/.venv/lib/python3.10/site-packages (from flask>=2.2.5->Flask-SQLAlchemy->-r requirements.txt (line 1)) (8.1.7)
    Requirement already satisfied: Jinja2>=3.1.2 in /home/myproject/.venv/lib/python3.10/site-packages (from flask>=2.2.5->Flask-SQLAlchemy->-r requirements.txt (line 1)) (3.1.2)
    Requirement already satisfied: greenlet!=0.4.17 in /home/myproject/.venv/lib/python3.10/site-packages (from sqlalchemy>=1.4.18->Flask-SQLAlchemy->-r requirements.txt (line 1)) (2.0.2)
    Requirement already satisfied: typing-extensions>=4.2.0 in /home/myproject/.venv/lib/python3.10/site-packages (from sqlalchemy>=1.4.18->Flask-SQLAlchemy->-r requirements.txt (line 1)) (4.7.1)
    Requirement already satisfied: MarkupSafe>=2.0 in /home/myproject/.venv/lib/python3.10/site-packages (from Jinja2>=3.1.2->flask>=2.2.5->Flask-SQLAlchemy->-r requirements.txt (line 1)) (2.1.3)
    Building wheels for collected packages: mysqlclient
      Building wheel for mysqlclient (pyproject.toml) ... done
      Created wheel for mysqlclient: filename=mysqlclient-2.2.0-cp310-cp310-linux_x86_64.whl size=123666 sha256=984152e71d3771685c41feb0a802f0145cbb7fd8702dced6090750b271b4722f
      Stored in directory: /root/.cache/pip/wheels/a4/f8/fd/0399687c0abd03c10c975ed56c692fcd3d0fb80440b5a661f1
    Successfully built mysqlclient
    Installing collected packages: mysqlclient
    Successfully installed mysqlclient-2.2.0

    Hãy xây dựng project của bạn theo cấu trúc như dưới đây.

    ../myapp/
    ├── SQLAlchemy.py
    └── templates
        ├── base.html
        ├── home.html
        ├── login.html
        └── user.html

    Các file login.html, base.htmlhome.html mình sẽ giữ nguyên ở bài trước.

    Nội dung file user.html.

    {% extends "base.html" %}
    {% block title %}Login Page{% endblock %}
    
    {% block content %}
    <h2>Hello {{user}}</h2>
    {% with messages = get_flashed_messages() %}
        {% if messages %}
            {% for m in messages %}
                <p>{{m}}</p>
            {% endfor %}
        {% endif %}
    {% endwith %}
    <div style="margin-left: 50px;">
        <form action="#" method="post">
            <label for="email">Email</label>
            <input type="email" name="email" placeholder="Enter email..." value="{{email if email}}"></input>
            <button style="background-color: slateblue; color: white;" type="submit">Submit</button>
            <input type="name" name="name" placeholder="Enter name..." value="{{user if user}}"></input>
            <button style="background-color: slateblue; color: white;" type="submit">Delete</button>
        </form>
    </div>
    {% endblock %}

    Đoạn code HTML trên mình chỉnh sửa phần (form) trong trang web và dưới đây là giải thích từng phần của nó:

    • <form action="#" method="post">: Đây là phần bắt đầu của biểu mẫu. Nó xác định phương thức HTTP (POST) và URL mục tiêu (action). Trong trường hợp này, action được đặt thành "#" nghĩa là biểu mẫu sẽ gửi yêu cầu POST đến chính trang web hiện tại.
    • <label for="email">Email</label>: Đây là một nhãn (label) cho trường nhập email. Thuộc tính for của nhãn được liên kết với thuộc tính id của trường nhập dữ liệu email, giúp cải thiện khả năng tương tác của người dùng.
    • <input type="email" name="email" placeholder="Enter email..." value="{{email if email}}">: Đây là trường nhập dữ liệu email. Các thuộc tính quan trọng là:
      • type="email": Xác định loại dữ liệu mà trường này sẽ chấp nhận, trong trường hợp này là địa chỉ email.
      • name="email": Đặt tên cho trường nhập, được sử dụng để xác định dữ liệu trong yêu cầu khi biểu mẫu được gửi đi.
      • placeholder="Enter email...": Hiển thị một dòng văn bản mà người dùng có thể thấy bên trong trường nhập, đóng vai trò hướng dẫn cho họ.
      • value="{{email if email}}": Giá trị mặc định của trường nhập. Trong Flask, {{...}} được sử dụng để thay thế giá trị từ biến Python trong template. Trong trường hợp này, nếu biến email tồn tại (không rỗng), thì giá trị mặc định của trường nhập sẽ là giá trị của biến email.
    • <button style="background-color: slateblue; color: white;" type="submit">Submit</button>: Đây là nút gửi biểu mẫu. Nút này có văn bản là “Submit” và sẽ gửi yêu cầu POST khi người dùng nhấn vào nó. Thuộc tính style được sử dụng để định dạng giao diện người dùng của nút.
    • <input type="name" name="name" placeholder="Enter name..." value="{{user if user}}">: Đây là trường nhập dữ liệu tên. Các thuộc tính tương tự như trường email, bao gồm type, name, placeholder, và value. Trong trường hợp này, giá trị mặc định của trường nhập được thiết lập bằng giá trị của biến user nếu biến này tồn tại.
    • <button style="background-color: slateblue; color: white;" type="submit">Delete</button>: Đây là nút “Delete” cho việc xóa tài khoản người dùng. Nút này cũng gửi yêu cầu POST khi người dùng nhấn vào nó và có một giao diện người dùng tương tự như nút “Submit”.

    Nội dung file SQLAlchemy.py.

    Phần này sẽ tạo một ứng dụng web Flask đơn giản để quản lý đăng nhập người dùng và lưu trữ thông tin người dùng trong cơ sở dữ liệu MySQL.

    from flask import Flask, redirect, url_for, render_template, request, session
    from datetime import timedelta
    from flask.helpers import flash
    from flask_sqlalchemy import SQLAlchemy
    
    myapp = Flask(__name__)
    myapp.config["SECRET_KEY"] = "hoanghd-secret-key"
    myapp.config["SQLALCHEMY_DATABASE_URI"] = "mysql://db_username:db_password@db_host/db_name"
    myapp.permanent_session_lifetime = timedelta(minutes=1)
    
    db = SQLAlchemy(myapp)
    
    class User(db.Model):
        user_id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(100))
        email = db.Column(db.String(100))
    
        def __init__(self, name, email):
            self.name = name
            self.email = email
    
    @myapp.route('/home')
    def hello_world():
        return render_template("home.html")
    
    @myapp.route('/login', methods=["POST", "GET"])
    def login():
        if request.method == "POST":
            user_name = request.form["name"]
            session.permanent = True
            if user_name:
                session["user"] = user_name
                found_user = User.query.filter_by(name=user_name).first()
                if found_user:
                    session["email"] = found_user.email
                else:
                    user = User(user_name, "temp@gmail.com")
                    db.session.add(user)
                    db.session.commit()
                    flash("Created in DB!")
                return redirect(url_for("user"))
        if "user" in session:
            return redirect(url_for("user"))
        return render_template("login.html")
    
    @myapp.route("/user", methods=["POST", "GET"])
    def user():
        email = None
        if "user" in session:
            name = session["user"]
            if request.method == "POST":
                if not request.form["email"] and request.form["name"]:
                    User.query.filter_by(name=name).delete()
                    db.session.commit()
                    flash("Deleted user!")
                    return redirect(url_for("log_out"))
                else:
                    email = request.form["email"]
                    session["email"] = email
                    found_user = User.query.filter_by(name=name).first()
                    found_user.email = email
                    db.session.commit()
                    flash("Email updated!")
                    print(email)
            return render_template("user.html", user=name, email=email)
        else:
            return redirect(url_for("login"))
    
    @myapp.route("/logout")
    def log_out():
        session.pop("user", None)
        return redirect(url_for("login"))
    
    if __name__ == "__main__":
        myapp.run(debug=True, host='0.0.0.0', port=5000)
    • Import các thư viện và modules cần thiết:
      • Flask: Được sử dụng để tạo ứng dụng web Flask.
      • redirect, url_for, render_template, request, session: Các chức năng và modules từ Flask cho việc định tuyến, hiển thị template HTML, xử lý yêu cầu từ người dùng và quản lý phiên làm việc.
      • timedelta: Được sử dụng để đặt thời gian sống của phiên làm việc (session lifetime).
      • flash: Dùng để hiển thị thông báo cho người dùng.
      • SQLAlchemy: Thư viện ORM (Object-Relational Mapping) cho việc tương tác với cơ sở dữ liệu MySQL.
    • Khởi tạo ứng dụng Flask:
      • Tạo một đối tượng Flask với tên myapp.
      • Đặt cấu hình cho ứng dụng, bao gồm cấu hình cho việc bảo mật (SECRET_KEY), đường dẫn cơ sở dữ liệu MySQL (SQLALCHEMY_DATABASE_URI), và đặt thời gian sống của phiên làm việc (permanent_session_lifetime).
    • Tạo đối tượng cơ sở dữ liệu SQLAlchemy:
      • Sử dụng SQLAlchemy để kết nối và tương tác với cơ sở dữ liệu MySQL.
      • Định nghĩa một lớp User để biểu diễn các bản ghi trong bảng User trong cơ sở dữ liệu. Các trường trong bảng bao gồm user_id, name, và email.
    • Định nghĩa các route và xử lý chức năng:
      • @myapp.route('/home'): Định nghĩa một route cho trang chủ. Nó trả về một template HTML là “home.html” khi người dùng truy cập.
      • @myapp.route('/login', methods=["POST", "GET"]): Định nghĩa route cho trang đăng nhập. Nó xử lý cả yêu cầu GET và POST. Nếu người dùng đã đăng nhập, họ sẽ được chuyển hướng đến trang /user. Nếu người dùng gửi một biểu mẫu POST (đăng nhập), nó sẽ kiểm tra thông tin đăng nhập, tạo hoặc cập nhật thông tin người dùng trong cơ sở dữ liệu và đặt phiên làm việc (session) cho người dùng. Đồng thời, nếu người dùng đã tồn tại, nó sẽ lấy thông tin email của họ.
      • @myapp.route("/user", methods=["POST", "GET"]): Định nghĩa route cho trang người dùng. Nếu người dùng đã đăng nhập, họ có thể thấy thông tin cá nhân của họ và cập nhật email. Nếu người dùng gửi biểu mẫu POST để cập nhật email hoặc xóa tài khoản, thì thông tin sẽ được cập nhật trong cơ sở dữ liệu.
      • @myapp.route("/logout"): Định nghĩa route cho việc đăng xuất. Nó xóa phiên làm việc của người dùng và chuyển hướng họ đến trang đăng nhập.
    • Cuối cùng, ứng dụng kiểm tra xem nó có đang chạy trong chế độ main (__name__ == "__main__") và nếu vậy, nó sẽ bắt đầu chạy ứng dụng Flask trên máy chủ cục bộ, lắng nghe các yêu cầu từ người dùng trên cổng 5000.

    Nhớ vào DB tạo thủ công Database, Table và các trường cho nó nhé.

    Hãy chạy ứng dụng SQLAlchemy của bạn.

    $ python SQLAlchemy.py 
     * Serving Flask app 'SQLAlchemy.py'
     * Debug mode: on
     * Running on http://127.0.0.1:5000
     * Running on http://192.168.13.200:5000
    Press CTRL+C to quit
     * Restarting with stat
     * Debugger is active!
     * Debugger PIN: 176-096-173

    Kết quả.

    Nếu bạn chưa xóa dữ liệu người dùng thì trong DB của bạn sẽ có thông tin của người dùng nhé.

    Tới đây bạn đã biết cách sử dụng SQLAlchemy để truy vấn tới MySQL tạo một form đơn giản rồi, chúc các bạn thành công

    Bài viết gần đây

    spot_img

    Related Stories

    Leave A Reply

    Please enter your comment!
    Please enter your name here

    Đăng ký nhận thông tin bài viết qua email