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.html
và home.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ínhfor
của nhãn được liên kết với thuộc tínhid
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ếnemail
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ếnemail
.
<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ínhstyle
đượ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ồmtype
,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ếnuser
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 một đối tượng Flask với tên
- 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ảngUser
trong cơ sở dữ liệu. Các trường trong bảng bao gồmuser_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