KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
1
Câu :1 (5 điểm)
g
CHÉP MÃ NGUỒN VÀ MÀN HÌNH KẾT QU
Chép màn hình thể ực quan TRƯỜNG id là khóa chính (Primary key)tr
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
import os
app = Flask(__name__)
# Cấu hình cơ sở dữ ệu PostgreSQLli
app.config['SQLALCHEMY_DATABASE_URI'] =
'postgresql://postgres:123@localhost:5432/flask_db'
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
2
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
def __repr__(self):
return '<Role %r>' % self.name
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
password = db.Column(db.String(128)) # Thêm cột password
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
role = db.relationship('Role', backref=db.backref('users', lazy=True))
def __repr__(self):
return '<User %r>' % self.username
@app.route('/') # Đảm bảo route này đã được định nghĩa
def home():
return 'Hello, Flask!'
if __name__ == '__main__':
with app.app_context():
db.create_all() # Tạo tất cả các bảng đã định nghĩa
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
3
app.run(debug=True)
Màn hình kết quả :
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
4
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
5
Câu 2: (5 điểm)
CHÉP MÃ NGUỒN VÀ MÀN HÌNH KẾT QU
Phn hướng dẫn thực hành sau
Tham khảo https://deneb.click/migration-from-tkinter- -flask/to
Di chuyển từ Tkinter sang Flask
Thư viện phổ biến nhất để tạo GUI trong Python là Tkinter, đây là một phần của cài đặt
Python chuẩn. Tkinter là một công cụ trưởng thành và ổn định, được chuyển rộng rãi và
tương đối dễ học. Tuy nhiên, nó cũng khá cũ với nhiều nhược điểm, trong số đó, nó có một
bộ ện ích hạn chế ặc dù mô hình đơn giản dễ học, Tkinter cũng trở nên cồng kềnh vớti . M i
các giao diện phức tạp hơn. Trên hết, nó không hỗ phát triể ng dụng di động và web.tr n
Cửa sổ Tkinter
Giao diện người dùng Flask
Giao diện web
Có mộ dụng máy tính để bàn truyền thống được phát triển trong Tkinter, chúng tôi t ứng
muốn điều chỉnh nó theo các tiêu chuẩn hiện đại bằng cách triển khai GUI web. Tuy nhiên,
việc di chuyển có thể là một nhiệm vụ tốn thời gian. Một trong những cách tiếp cận là biến
nó thành một quá trình tiến hóa, tức là chúng tôi cho phép các tình huống mà chúng tôi sẽ
cả máy tính để bàn và ứng dụng web cùng một lúc. Nó cho phép các nhà phát trin dần
dần thay thế các cửa sổ máy tính để bàn bằng các điều khiển web, điều này cho phép họ
tránh làm việc với hai phiên bản của một ứng dụng (Tkinter và Flask). Trong trường hợp
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
6
như vậy, cả hai mô-đun GUI sẽ hợp tác và giao tiếp với nhau. Sau khi phiên bản Flask cuối
cùng đã sẵn sàng, chúng tôi có thể xóa mã Tkinter không cần thiết.
Dưới đây, tôi trình bày bản nháp của một cách tiếp cận như vậy. Cả hai GUI, được biểu
diễn bởi các hàm tk_main và flask_main, phải nằm trong các luồng riêng biệt. Để giảm số
luồng, chúng ta có thể sử dụng lại luồng chính và gán cho nó GUI Tkinter. Đối với GUI
Flask, chúng ta tạo một luồng mi (xem ví dụ tại đây để biết thông tin về các luồng
Python). Trong phần Tkinter, được biểu diễn bởi lớp , chúng ta định nghĩa một nút TkApp
mở trình duyệt web có trang web Flask. Đồng thời, chúng ta truyền một đối số cho Flask
thông qua một biến toàn cục, hơi cồng knh, nhưng tôi cố gắng đơn giản hóa trong ví d
này. Sau khi chạy ví dụ, chúng ta có thể sử dụng đồng thời cả hai GUI – một tính năng hữu
ích khi di chuyể ứng dụng của mình. Trong trường hợp có sự cố xảy ra với cửa sổ Flask n
mới của bạ bạn vẫn có bản sao lưu Tkinter giúp ứng dụng luôn có thể sử dụng đượn c.
1 ĐIỂM
Giải thích mã nguồn
LỆNH THỰC HIỆN
Dùng để chạy Flask
trong một luồng
(thread) riêng biệt
import threading
Tạo giao diện người
dùng với một nút
nhấn trong cửa sổ
Tkinter.
from tkinter import Tk, Button, END, mainloop
Khởi tạo ứng dụng
Flask để làm việc
với HTTP requests.
from flask import Flask
Mở một URL trong
trình duyệt mặc
định của hệ thống.
import webbrowser
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
7
Khởi tạo mộ ứng t
dụng Flask với tên
flask_app.
flask_app = Flask(__name__)
Lớp TkApp
class TkApp:
__init__ khởi tạo
giao diện Tkinter
với một nút nhấn.
def __init__(self, master):
self.button = Button(master, text="Show in
webbrowser",
command=self.btn_callback)
self.button.pack()
btn_callback: Hàm
này chạy khi nhấn
nút, thiết lập biến
var với thông điệp
"Greetings from
Tkinter" và mở
URL
http://localhost:5001
trên trình duyệt.
def btn_callback(self):
global var
var = 'Greetings from Tkinter'
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
8
webbrowser.open("http://localhost:5001")
Khởi tạo route /
trong Flask:
@flask_app.route('/', methods=['POST', 'GET'])
def flask_index():
Khi truy cập, Flask
trả về giá trị của
biến var (thông điệp
từ Tkinter).
return var
Hàm này khởi động
Flask trên localhost
cổng 5001.
def flask_main():
flask_app.run(debug=False, host="localhost", port=5001)
Hàm tk_main khởi
tạo giao diện
Tkinter với cửa sổ
chính root và vào
ng lặp sự kiện
(event loop) của
Tkinter.
def tk_main():
root = Tk()
TkApp(root)
root.mainloop()
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
9
if __name__ == "__main__":
Khởi động Flask
trong một luồng
(flask_thread) với
daemon=True để
Flask đóng khi
chương trình chính
kết thúc.
flask_thread = threading.Thread(target=flask_main)
flask_thread.daemon = True
Bắt đầu giao diện
Tkinter (tk_main).
flask_thread.start()
tk_main()
view rawintro.py hosted with by GitHub
Màn hình kết quả :
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
10
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
11
Di chuyển tiện ích
Trong bước tiếp theo, chúng ta sẽ di chuyển một tiện ích Tkinter mẫ — listbox. Hãy bu t
đầu với một đoạn mã lộn xộn kết hợp giữa tính toán và trình bày dữ liệu.
1 ĐIỂM
Giải thích mã nguồn
LỆNH THỰC HIỆN
Tạo giao diện đồ họa
đơn giản với danh sách
(Listbox).
from tkinter import Tk, Listbox, END, mainloop
Tạo và làm việc với cơ
sở dữ ệu SQLite li
trong bộ nhớ.
import sqlite3
Tạo cửa sổ chính của
ứng dụng Tkinter và
gán nó vào biến
master.
master = Tk()
Tạo một Listbox (danh
sách) để ển thị dữ hi
liệu, đặt nó trong cửa
sổ master, và sử dụ ng
pack() để ển thị hi
Listbox trên giao diện.
listbox = Listbox(master)
listbox.pack()
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
12
Tạo một cơ sở dữ liệu
SQLite trong bộ nh
(không lưu vào file).
connection = sqlite3.connect(':memory:')
Tạo con trỏ (cursor) để
thực thi các lệnh SQL.
cursor = connection.cursor()
Tạo bảng foo với hai
cột
cursor.execute('''CREATE TABLE foo
id: Kiểu số nguyên
(INTEGER), tự động
tăng
(AUTOINCREMENT),
làm khóa chính.
(id INTEGER PRIMARY KEY
AUTOINCREMENT,
Bar : ểu chuỗKi i
(TEXT), dùng để lưu
trữ gtrị.
bar TEXT)''')
Chuẩn bị lệnh SQL cho
thao tác thêm dữ liệu
vào bảng foo với cột
bar.
sql = 'INSERT INTO foo (bar) values (?)'
Thực hiện vòng lặp để
thêm dữ ệu vào bả .li ng
Chạy từ i = 0 đến i = 4,
mỗi lần thêm một bản
ghi với bar chứa giá tr
từ 1 đế 5 (i + 1n ).
for i in range(5):
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
13
cursor.execute(sql,
(i+1,)): Thực hiện lệnh
SQL, với giá trị của
bar được truyền vào
qua (i+1,).
cursor.execute(sql, (i+1,))
Lấy tất cả các bản ghi
từ bảng foo.
cursor.execute('SELECT * from foo')
Trả về danh sách chứa
tất cả các bản ghi lấy
được.
for row in cursor.fetchall():
Với mỗi dòng (row)
trong kết quả, lấy cột
id (row[0]) và chèn vào
cuối Listbox.
listbox.insert(END, row[0])
Run
mainloop()
view rawstep_1.py hosted with by GitHub
Màn hình kết quả :
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
14
Mã này đang hoạt động nhưng được viết trái với các nguyên tắc của kỹ thuật phần mềm.
Để sẵn sàng di chuyển tức là thay thế Tkinter bằng HTML GUI, chúng ta phải trích xuất
mã chịu trách nhiệm hiển thị dữ liệu. Chức năng GUI chỉ nên xử lý việc trình bày dữ liệu
và tránh xa việc xử lý dữ liệu.
1 ĐIỂM
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
15
Giải thích mã nguồn
LỆNH THỰC HIỆN
Tạo giao diện đồ họa
đơn giản với một
Listbox.
from tkinter import Tk, Listbox, Button, END, mainloop
Tạo và làm việc với cơ
sở dữ ệu SQLite li
trong bộ nhớ.
import sqlite3
Tạo cửa sổ chính
master củ ng dụng a
Tkinter.
master = Tk()
def prepare_data():
Tạo cơ sở dữ liệu
SQLite trong bộ nhớ.
connection = sqlite3.connect(':memory:')
Tạo con trỏ cursor để
thực thi các lệnh SQL.
cursor = connection.cursor()
Tạo bảng foo với hai
cột
cursor.execute('''CREATE TABLE foo
Kiểu số nguyên
(INTEGER), tự động
tăng
(AUTOINCREMENT),
làm khóa chính.
(id INTEGER PRIMARY KEY
AUTOINCREMENT,
bar: Kiểu chuỗi
(TEXT).
bar TEXT)''')
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
16
Chuẩn bị lệnh SQL để
chèn giá trị vào bảng
foo.
sql = 'INSERT INTO foo (bar) values (?)'
Thêm 5 bản ghi vào
bảng foo, giá trị bar từ
1 đến 5.
for i in range(5):
cursor.execute(sql, (i+1,))
Trả về con trỏ cursor,
giúp thực hiện các truy
vấn tiếp theo trên dữ
liệu đã chuẩn bị.
return(cursor)
def process_data(cursor):
Lấy tất cả bản ghi từ
bảng foo.
cursor.execute('SELECT * from foo')
Tạo danh sách trống
để lưu dữ u đã xử lý.li
data = list()
Duyệt qua từng dòng
trong kết quả truy vấn
for row in cursor.fetchall():
# here process the row, e.g. concatenate, compute,
replace, etc.
Thêm mỗi dòng vào
danh sách data.
data.append(row)
Trả về danh sách data
chứa các dòng dữ liệu
từ bảng foo.
return(data)
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
17
def show_data(parent, data):
Tạo một Listbox và đặt
nó trong cửa sổ chính
(parent).
listbox = Listbox(parent)
Hiển thị Listbox trên
giao diện
listbox.pack()
Duyệt qua từng dòng
dữ u trong datali
for row in data:
Chèn giá trị id (row[0])
từ mỗi dòng vào cuối
Listbox.
listbox.insert(END, row[0])
Gọi prepare_data để
tạo cơ sở dữ u, bảng li
và thêm dữ liệu; sau đó
trả về con trỏ cursor.
cursor = prepare_data()
Gọi process_data để
lấy và xử lý dữ u từ li
cơ sở dữ liệu.
data_processed = process_data(cursor)
Gọi show_data để hiển
thị dữ liệu trong
Listbox của giao diện.
show_data(master, data_processed)
mainloop()
view rawstep_2.py hosted with by GitHub
Màn hình kết quả :
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
18
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
19
Sau một số lần dọn dẹp, chúng tôi chia chức năng của mã thành các
hàm prepare_data process_data , và show_data . Đây là các hàm đơn giản mô hình hóa
nhim vụ thông thường của một số ứng dụng: chúng thu thập dữ ệu, xử lý dữ ệu và hiểli li n
thị kết quả. Các hàm trao đổi dữ liệu bằng cách sử dụng các cấu trúc con trỏ hoặc danh
sách . Những thay đổi này làm tăng thêm một số độ phức tạp cho mã nhưng cũng giúp việc
đưa ra các thay đổi dễ dàng hơn hoặc cho phép thử nghiệm hiệu quả hơn. Bây giờ chúng ta
đã sẵn sàng để thêm phần Flask, bao gồm lớp FlaskMyForm và
hàm flask_index . FlaskMyForm biểu thị một biểu mẫu nhóm các điều khiển HTML,
nhưng trong trường hợp đơn giản của chúng ta, nó chỉ có một tiện ích di
chuyển SelectField . Hàm flask_index đảm nhiệm việc cung cấp dữ liệu cho SelectField
hiển thị dữ liệu đó trên một trang web.
1 ĐIỂM
Giải thích mã nguồn
LỆNH THỰC HIỆN
import threading
Tạo giao diện đồ họa
với Tkinter
from tkinter import Tk, Listbox, Button, END, mainloop
Tạo cơ sở dữ ệu trong li
bộ nhớ và truy xuất dữ
liệu.
import sqlite3
Tạo ứng dụng web với
Flask, cho phép hiển
thị u mẫu HTML bi
trực tiếp từ chuỗi.
from flask import Flask, render_template_string
Tạo dropdown
(SelectField) trong
Flask.
from wtforms import SelectField
Mở trình duyệt web.
import webbrowser
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, H Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
20
Cung cấp tính năng tạo
biểu mẫu trong Flask
và yêu cầu
from flask_wtf import FlaskForm
flask_app = Flask(__name__)
Để bảo mật CSRF.
flask_app.secret_key = 'SHH!'
def prepare_data():
Kết nối đến một cơ sở
dữ u SQLite trong li
bộ nhớ (:memory:)
connection = sqlite3.connect(':memory:')
cursor = connection.cursor()
Tạo bảng foo với cột id
tự động tăng và cột bar
chứa dữ liệu kiểu
TEXT.
cursor.execute('''CREATE TABLE foo
(id INTEGER PRIMARY KEY
AUTOINCREMENT,
bar TEXT)''')
Chèn 5 bản ghi vào
bảng foo với các giá trị
từ 1 đế 5 cho bar.n
sql = 'INSERT INTO foo (bar) values (?)'
for i in range(5):

Preview text:

KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn Câu :1 (5 điểm) g
CHÉP MÃ NGUỒN VÀ MÀN HÌNH KẾT QUẢ
Chép màn hình thể trực quan TRƯỜNG id là khóa chính (Primary key) from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate import os app = Flask(__name__)
# Cấu hình cơ sở dữ liệu PostgreSQL
app.config['SQLALCHEMY_DATABASE_URI'] =
'postgresql://postgres:123@localhost:5432/flask_db' 1
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) migrate = Migrate(app, db) class Role(db.Model): __tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True) def __repr__(self): return '' % self.name class User(db.Model): __tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
password = db.Column(db.String(128)) # Thêm cột password
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
role = db.relationship('Role', backref=db.backref('users', lazy=True)) def __repr__(self): return '' % self.username
@app.route('/') # Đảm bảo route này đã được định nghĩa def home(): return 'Hello, Flask!' if __name__ == '__main__': with app.app_context():
db.create_all() # Tạo tất cả các bảng đã định nghĩa 2
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn app.run(debug=True) Màn hình kết quả : 3
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn 4
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn Câu 2: (5 điểm)
CHÉP MÃ NGUỒN VÀ MÀN HÌNH KẾT QUẢ
Phần hướng dẫn thực hành sau
Tham khảo https://deneb.click/migration-from-tkinter-to-flask/
Di chuyển từ Tkinter sang Flask
Thư viện phổ biến nhất để tạo GUI trong Python là Tkinter, đây là một phần của cài đặt
Python chuẩn. Tkinter là một công cụ trưởng thành và ổn định, được chuyển rộng rãi và
tương đối dễ học. Tuy nhiên, nó cũng khá cũ với nhiều nhược điểm, trong số đó, nó có một
bộ tiện ích hạn chế. Mặc dù mô hình đơn giản dễ học, Tkinter cũng trở nên cồng kềnh với
các giao diện phức tạp hơn. Trên hết, nó không hỗ trợ phát triển ứ
ng dụng di động và web. Cửa sổ Tkinter
Giao diện người dùng Flask Giao diện web
Có một ứng dụng máy tính để bàn truyền thống được phát triển trong Tkinter, chúng tôi
muốn điều chỉnh nó theo các tiêu chuẩn hiện đại bằng cách triển khai GUI web. Tuy nhiên,
việc di chuyển có thể là một nhiệm vụ tốn thời gian. Một trong những cách tiếp cận là biến
nó thành một quá trình tiến hóa, tức là chúng tôi cho phép các tình huống mà chúng tôi sẽ
có cả máy tính để bàn và ứng dụng web cùng một lúc. Nó cho phép các nhà phát triển dần
dần thay thế các cửa sổ máy tính để bàn bằng các điều khiển web, điều này cho phép họ
tránh làm việc với hai phiên bản của một ứng dụng (Tkinter và Flask). Trong trường hợp 5
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
như vậy, cả hai mô-đun GUI sẽ hợp tác và giao tiếp với nhau. Sau khi phiên bản Flask cuối
cùng đã sẵn sàng, chúng tôi có thể xóa mã Tkinter không cần thiết.
Dưới đây, tôi trình bày bản nháp của một cách tiếp cận như vậy. Cả hai GUI, được biểu
diễn bởi các hàm tk_main và flask_main, phải nằm trong các luồng riêng biệt. Để giảm số
luồng, chúng ta có thể sử dụng lại luồng chính và gán cho nó GUI Tkinter. Đối với GUI
Flask, chúng ta tạo một luồng mới (xem ví dụ tại đây để biết thông tin về các luồng
Python). Trong phần Tkinter, được biểu diễn bởi lớp TkApp , chúng ta định nghĩa một nút
mở trình duyệt web có trang web Flask. Đồng thời, chúng ta truyền một đối số cho Flask
thông qua một biến toàn cục, hơi cồng kềnh, nhưng tôi cố gắng đơn giản hóa trong ví dụ
này. Sau khi chạy ví dụ, chúng ta có thể sử dụng đồng thời cả hai GUI – một tính năng hữu
ích khi di chuyển ứ
ng dụng của mình. Trong trường hợp có sự cố xảy ra với cửa sổ Flask mới của bạn –
bạn vẫn có bản sao lưu Tkinter giúp ứng dụng luôn có thể sử dụng được. 1 ĐIỂM
Giải thích mã nguồn LỆNH THỰC HIỆN
Dùng để chạy Flask import threading trong một luồng (thread) riêng biệt
Tạo giao diện người
from tkinter import Tk, Button, END, mainloop dùng với một nút
nhấn trong cửa sổ Tkinter.
Khởi tạo ứng dụng
from flask import Flask
Flask để làm việc với HTTP requests. Mở một URL trong import webbrowser trình duyệt mặc
định của hệ thống. 6
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
Khởi tạo một ứng
flask_app = Flask(__name__)
dụng Flask với tên flask_app. Lớp TkApp class TkApp: __init__ khởi tạo
def __init__(self, master): giao diện Tkinter
với một nút nhấn.
self.button = Button(master, text="Show in webbrowser",
command=self.btn_callback) self.button.pack() btn_callback: Hàm
def btn_callback(self): này chạy khi nhấn
nút, thiết lập biến
var với thông điệp "Greetings from Tkinter" và mở URL http://localhost:5001 trên trình duyệt. global var
var = 'Greetings from Tkinter' 7
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
webbrowser.open("http://localhost:5001") Khởi tạo route /
@flask_app.route('/', methods=['POST', 'GET']) trong Flask: def flask_index(): Khi truy cập, Flask return var
trả về giá trị của
biến var (thông điệp từ Tkinter).
Hàm này khởi động def flask_main(): Flask trên localhost cổng 5001.
flask_app.run(debug=False, host="localhost", port=5001) Hàm tk_main khởi def tk_main(): tạo giao diện
Tkinter với cửa sổ chính root và vào
vòng lặp sự kiện (event loop) của Tkinter. root = Tk() TkApp(root) root.mainloop() 8
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
if __name__ == "__main__": Khởi động Flask
flask_thread = threading.Thread(target=flask_main) trong một luồng (flask_thread) với daemon=True để Flask đóng khi chương trình chính kết thúc.
flask_thread.daemon = True
Bắt đầu giao diện flask_thread.start() Tkinter (tk_main). tk_main()
view rawintro.py hosted with by GitHub
Màn hình kết quả : 9
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn 10
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
Di chuyển tiện ích
Trong bước tiếp theo, chúng ta sẽ di chuyển một tiện ích Tkinter mẫu — listbox. Hãy bắt
đầu với một đoạn mã lộn xộn kết hợp giữa tính toán và trình bày dữ liệu. 1 ĐIỂM
Giải thích mã nguồn LỆNH THỰC HIỆN
Tạo giao diện đồ họa
from tkinter import Tk, Listbox, END, mainloop
đơn giản với danh sách (Listbox).
Tạo và làm việc với cơ import sqlite3 sở dữ l ệ i u SQLite trong bộ nhớ.
Tạo cửa sổ chính của master = Tk()
ứng dụng Tkinter và gán nó vào biến master.
Tạo một Listbox (danh
listbox = Listbox(master) sách) để h ể i n thị dữ
liệu, đặt nó trong cửa
sổ master, và sử dụng
pack() để hiển thị
Listbox trên giao diện. listbox.pack() 11
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
Tạo một cơ sở dữ liệu
connection = sqlite3.connect(':memory:')
SQLite trong bộ nhớ
(không lưu vào file).
Tạo con trỏ (cursor) để
cursor = connection.cursor()
thực thi các lệnh SQL.
Tạo bảng foo với hai
cursor.execute('''CREATE TABLE foo cột
id: Kiểu số nguyên
(id INTEGER PRIMARY KEY
(INTEGER), tự động AUTOINCREMENT, tăng (AUTOINCREMENT), làm khóa chính. Bar : Kiểu chuỗi bar TEXT)''')
(TEXT), dùng để lưu trữ giá trị.
Chuẩn bị lệnh SQL cho sql = 'INSERT INTO foo (bar) values (?)'
thao tác thêm dữ liệu
vào bảng foo với cột bar.
Thực hiện vòng lặp để for i in range(5): thêm dữ l ệ i u vào bảng .
Chạy từ i = 0 đến i = 4,
mỗi lần thêm một bản
ghi với bar chứa giá trị
từ 1 đến 5 (i + 1). 12
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn cursor.execute(sql,
cursor.execute(sql, (i+1,))
(i+1,)): Thực hiện lệnh
SQL, với giá trị của
bar được truyền vào qua (i+1,).
Lấy tất cả các bản ghi
cursor.execute('SELECT * from foo') từ bảng foo.
Trả về danh sách chứa
for row in cursor.fetchall():
tất cả các bản ghi lấy được.
Với mỗi dòng (row)
listbox.insert(END, row[0])
trong kết quả, lấy cột
id (row[0]) và chèn vào cuối Listbox. Run mainloop()
view rawstep_1.py hosted with by GitHub
Màn hình kết quả : 13
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
Mã này đang hoạt động nhưng được viết trái với các nguyên tắc của kỹ thuật phần mềm.
Để sẵn sàng di chuyển tức là thay thế Tkinter bằng HTML GUI, chúng ta phải trích xuất
mã chịu trách nhiệm hiển thị dữ liệu. Chức năng GUI chỉ nên xử lý việc trình bày dữ liệu
và tránh xa việc xử lý dữ liệu. 1 ĐIỂM 14
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
Giải thích mã nguồn LỆNH THỰC HIỆN
Tạo giao diện đồ họa
from tkinter import Tk, Listbox, Button, END, mainloop
đơn giản với một Listbox.
Tạo và làm việc với cơ import sqlite3 sở dữ l ệ i u SQLite trong bộ nhớ.
Tạo cửa sổ chính master = Tk() master của ứ ng dụng Tkinter. def prepare_data():
Tạo cơ sở dữ liệu
connection = sqlite3.connect(':memory:')
SQLite trong bộ nhớ.
Tạo con trỏ cursor để
cursor = connection.cursor()
thực thi các lệnh SQL.
Tạo bảng foo với hai
cursor.execute('''CREATE TABLE foo cột Kiểu số nguyên
(id INTEGER PRIMARY KEY
(INTEGER), tự động AUTOINCREMENT, tăng (AUTOINCREMENT), làm khóa chính. bar: Kiểu chuỗi bar TEXT)''') (TEXT). 15
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
Chuẩn bị lệnh SQL để
sql = 'INSERT INTO foo (bar) values (?)'
chèn giá trị vào bảng foo. Thêm 5 bản ghi vào for i in range(5):
bảng foo, giá trị bar từ 1 đến 5.
cursor.execute(sql, (i+1,))
Trả về con trỏ cursor, return(cursor)
giúp thực hiện các truy
vấn tiếp theo trên dữ
liệu đã chuẩn bị.
def process_data(cursor):
Lấy tất cả bản ghi từ
cursor.execute('SELECT * from foo') bảng foo.
Tạo danh sách trống data = list() để lưu dữ l ệ i u đã xử lý.
Duyệt qua từng dòng
for row in cursor.fetchall():
trong kết quả truy vấn
# here process the row, e.g. concatenate, compute, replace, etc. Thêm mỗi dòng vào data.append(row) danh sách data.
Trả về danh sách data return(data)
chứa các dòng dữ liệu từ bảng foo. 16
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
def show_data(parent, data):
Tạo một Listbox và đặt listbox = Listbox(parent)
nó trong cửa sổ chính (parent).
Hiển thị Listbox trên listbox.pack() giao diện
Duyệt qua từng dòng for row in data: dữ l ệ i u trong data
Chèn giá trị id (row[0])
listbox.insert(END, row[0])
từ mỗi dòng vào cuối Listbox.
Gọi prepare_data để
cursor = prepare_data()
tạo cơ sở dữ l ệ i u, bảng
và thêm dữ liệu; sau đó
trả về con trỏ cursor.
Gọi process_data để
data_processed = process_data(cursor)
lấy và xử lý dữ l ệ i u từ cơ sở dữ liệu.
Gọi show_data để hiển
show_data(master, data_processed)
thị dữ liệu trong
Listbox của giao diện. mainloop()
view rawstep_2.py hosted with by GitHub
Màn hình kết quả : 17
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn 18
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
Sau một số lần dọn dẹp, chúng tôi chia chức năng của mã thành các
hàm prepare_data , process_data show_data . Đây là các hàm đơn giản mô hình hóa
nhiệm vụ thông thường của một số ứng dụng: chúng thu thập dữ l ệ
i u, xử lý dữ l ệ i u và hiển
thị kết quả. Các hàm trao đổi dữ liệu bằng cách sử dụng các cấu trúc con trỏ hoặc danh
sách . Những thay đổi này làm tăng thêm một số độ phức tạp cho mã nhưng cũng giúp việc
đưa ra các thay đổi dễ dàng hơn hoặc cho phép thử nghiệm hiệu quả hơn. Bây giờ chúng ta
đã sẵn sàng để thêm phần Flask, bao gồm lớp FlaskMyForm
hàm flask_index . FlaskMyForm biểu thị một biểu mẫu nhóm các điều khiển HTML,
nhưng trong trường hợp đơn giản của chúng ta, nó chỉ có một tiện ích di
chuyển SelectField . Hàm flask_index đảm nhiệm việc cung cấp dữ liệu cho SelectField
hiển thị dữ liệu đó trên một trang web. 1 ĐIỂM
Giải thích mã nguồn LỆNH THỰC HIỆN import threading
Tạo giao diện đồ họa
from tkinter import Tk, Listbox, Button, END, mainloop với Tkinter
Tạo cơ sở dữ liệu trong import sqlite3
bộ nhớ và truy xuất dữ liệu.
Tạo ứng dụng web với
from flask import Flask, render_template_string
Flask, cho phép hiển thị b ể i u mẫu HTML
trực tiếp từ chuỗi. Tạo dropdown
from wtforms import SelectField (SelectField) trong Flask.
Mở trình duyệt web. import webbrowser 19
KIỂM TRA GKL2 PYTHON NÂNG CAO
Nhóm:0202,MaSV:2274802010318, Họ và Tên:Nguyễn Nhật Huy
Thời gian: 3g35-6g00 chiều, ngày 05/11/2024.
Nộp bài lên fit-lAB VÀ gửi đến email: anh.th@vlu.edu.vn
Cung cấp tính năng tạo from flask_wtf import FlaskForm
biểu mẫu trong Flask và yêu cầu
flask_app = Flask(__name__)
Để bảo mật CSRF.
flask_app.secret_key = 'SHH!' def prepare_data():
Kết nối đến một cơ sở
connection = sqlite3.connect(':memory:') dữ l ệ i u SQLite trong bộ nhớ (:memory:)
cursor = connection.cursor()
Tạo bảng foo với cột id
cursor.execute('''CREATE TABLE foo
tự động tăng và cột bar
chứa dữ liệu kiểu TEXT.
(id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT)''') Chèn 5 bản ghi vào
sql = 'INSERT INTO foo (bar) values (?)'
bảng foo với các giá trị
từ 1 đến 5 cho bar. for i in range(5): 20