Hướng dẫn python web form builder - trình tạo biểu mẫu web python

Trong phần này, chúng ta sẽ cùng tìm hiểu về khái niệm Web Form và cách sử dụng Web Form trong Flask.

Để giúp cho bạn dễ theo dõi, sau đây là danh sách các bài viết trong loạt bài hướng dẫn này:

  • Phần 1: Hello, World
  • Phần 2: Tìm hiểu về template
  • Phần 3: Tìm hiểu về Web Forms (bài viết này)
  • Phần 4: Sử dụng cơ sở dữ liệu
  • Phần 5: Xử lý đăng nhập
  • Phần 6: Hồ sơ cá nhân và ảnh đại diện
  • Phần 7: Xử lý lỗi
  • Phần 8: Tạo chức năng follower
  • Phần 9: Phân trang
  • Phần 10: Hỗ trợ email
  • Phần 11: Nâng cấp giao diện
  • Phần 12: Xử lý thời gian
  • Phần 13: Hỗ trợ đa ngôn ngữ
  • Phần 14: Sử dụng Ajax
  • Phần 15: Tinh chỉnh cấu trúc ứng dụng
  • Phần 16: Hỗ trợ tìm kiếm
  • Phần 17: Triển khai ứng dụng trên Linux
  • Phần 18: Triển khai ứng dụng với Heroku
  • Phần 19: Triển khai ứng dụng với Docker
  • Phần 20: JavaScript nâng cao
  • Phần 21: Thông báo cho người sử dụng
  • Phần 22: Tìm hiểu về tác vụ nền
  • Phần 23: Xây dựng API

Bạn có thể truy cập mã nguồn cho phần này tại GitHub.

Trong Phần 2, chúng ta đã tạo ra một template đơn giản cho trang chủ của ứng dụng và dùng các đối tượng giả lập cho các thành phần mà chúng ta chưa xây dựng như là đối tượng người sử dụng, các bài viết. Trong chương này, chúng ta sẽ tìm hiểu kỹ hơn về các điểm yếu của ứng dụng cho đến thời điểm này, đặt biệt là vấn đề tiếp nhận và xử lý những yêu cầu của người sử dụng thông qua Web form.

Một cách tổng quát, Web form (đừng nhầm lẫn với khái niệm Web form trong các ứng dụng ASP/ASP.NET truyền thống nhé, chúng không có liên quan gì với nhau mặc dù có cùng tên gọi) là một trong những thành phần cơ bản của bất kỳ ứng dụng Web nào. Chúng ta sẽ dùng Web form để người sử dụng có thể gởi dữ liệu như là bài viết, thông tin đăng nhập từ trình duyệt đến ứng dụng của chúng ta.

Trước khi bắt đầu phần mới, hãy chắc rằng ứng dụng myblog mà chúng ta đã xây dựng được thiết lập và chạy thành công.

Giới thiệu Flask-WTF

Để xử lý Web form trong ứng dụng, chúng ta sẽ dùng thư viện mở rộng (extension) Flask-WTF. Đây là một giao diện cho gói WTForms được tích hợp với Flask. Đây là thư viện mở rộng đầu tiên mà chúng ta sử dụng, nhưng sẽ không phải là cuối cùng. Các thư viện mở rộng là một thành phần quan trọng trong hệ sinh thái của Flask bởi vì chúng cung cấp các giải pháp mà Flask không có (dù là cố tình hay vô ý).

Các thư viện mở rộng của Flask là các gói thư viện Python tiêu chuẩn được cài đặt bằng pip. Bạn có thể cài đặt Flask-WTF trong môi trường ảo của bạn như sau:

(myenv)$pip3 install flask-wtfmyenv)$pip3 install flask-wtf

Thiết lập cấu hình

Cho đến thời điểm này, ứng dụng của chúng ta vẫn còn rất sơ khai, và do đó, chúng ta không cần phải để ý nhiều đến vấn đề cấu hình (configuration). Nhưng đối với bất kỳ ứng dụng nào ngoại trừ các ứng dụng rất đơn giản, chúng ta sẽ thấy rằng Flask (và có thể bao gồm các thư viện mở rộng của Flask mà bạn dùng) cho phép chúng ta tự do trong việc thực hiện ở mức độ nhất định. Và khi bạn cần ra quyết định nào đó, bạn sẽ cho Flask biết thông qua một danh sách các tham số cấu hình.

Có một vài định dạng khác nhau trong việc cung cấp cấu hình cho ứng dụng. Giải pháp cơ bản nhất là định nghĩa các tham số cấu hình của bạn qua các khóa (key) trong file app.config. File này dùng kiểu dictionary để mô tả các tham số. Ví dụ như sau:

app=Flask(__name__)=Flask(__name__)

app.config['SECRET_KEY']='khong-doan-noi-dau'.config['SECRET_KEY']='khong-doan-noi-dau'

...cácthôngsốcầnthiếtkhác..cácthôngs cnthiếtkhác

Dù cấu trúc trên đây là đầy đủ cho việc định nghĩa cấu hình cho Flask, chúng ta vẫn nên tuân theo nguyên tắc phân chia các mối quan tâm (separation of concerns). Cụ thể hơn, thay vì đặt tất cả các thông số cấu hình vào trong mã khởi tạo của ứng dụng, chúng ta sẽ đặt nó vào một file cấu hình riêng rẽ.

Trong khuôn khổ loạt bài này, chúng ta sẽ theo quy ước là dùng một class để chứa tất cả các thông số cấu hình của ứng dụng. Để giữ cho cấu trúc chung của ứng dụng được gọn gàng, chúng ta sẽ tạo ra lớp cấu hình trong một module Python riêng biệt. Sau đây là các khai báo trong lớp cấu hình cho ứng dụng trong file config.py mà chúng ta sẽ lưu ở thư mục ngoài cùng của ứng dụng:

config.py: Cấu hình cho mã khóa: Cấu hình cho mã khóa

importosos

classConfig(object):Config(object):

    SECRET_KEY=os.environ.get('SECRET_KEY')or'khong-doan-noi-dau'SECRET_KEY=os.environ.get('SECRET_KEY')or'khong-doan-noi-dau'

Rất đơn giản phải không? Tham số cấu hình sẽ được định nghĩa là các biến bên trong lớp Config. Nếu chúng ta cần khai báo các tham số mới, chúng ta sẽ thêm các biến mới vào lớp này. Thậm chí nếu sau này chúng ta cần nhiều bộ tham số, chúng ta có thể tạo ra các lớp con của lớp này. Nhưng bây giờ tạm thời chúng ta không cần đi sâu.

Tham số cấu hình SECRET_KEY trong lớp Config là một phần rất quan trọng trong các ứng dụng Flask. Flask và một số cá thư viện mở rộng dùng giá trị của biến này với vai trò là khóa mã hóa để tạo ra các chữ ký hoặc các token bảo mật. Thư viện mở rộng Flask-WTF dùng khóa này để bảo vệ Web form khỏi một hình thức tấn công rất phổ biến là Cross-Site Request Forgery hay là CRSF. Dễ thấy từ tên gọi của tham số này, nó phải là một khóa bí mật bởi vì quyết định độ mạnh yếu của các chữ ký và token bảo mật để bảo vệ cho ứng dụng.

Giá trị của khóa bí mật này là một biểu thức với hai mệnh đề được ghép lại với nhau qua toán tử OR. Mệnh đề thức nhất sẽ tìm giá trị của một biến môi trường cũng gọi là SECRET_KEY. Mệnh đề thứ hai là một chuỗi được định nghĩa sẵn. Chúng ta sẽ dùng cách này thường xuyên để thiết lập các tham số cấu hình xuyên suốt loạt bài này. Lý do là nó cho phép chúng ta có thể sử dụng giá trị của khóa từ biến môi trường hoặc một chuỗi định sẵn một cách linh hoạt. Trong môi trường phát triển, ít có nguy cơ bảo mật thì chúng ta có thể không cần khai báo biến môi trường và do đó, ứng dụng sẽ sử dụng giá trị của chuỗi định sẵn. Tuy nhiên, khi sử dụng chính thức thì chúng ta sẽ thiết lập một giá trị riêng cho khóa này trong biến môi trường. Giá trị này là duy nhất và khó có thể đoán ra bởi các phần mềm hack, vì thế chúng ta có thể bảo đảm rằng những dữ liệu nhạy cảm không bị lộ.

Sau khi đã có file cấu hình, chúng ta cần cho Flask biết để lấy thông tin từ đó và dùng cho ứng dụng. Chúng ta làm điều này bằng cách cập nhật file __init__.py và thêm một dòng lệnh sử dụng hàm app.config.from_object() như sau:

app/__init__.py: cấu hình Flask cấu hình Flask

fromflask importFlaskflask importFlask

fromconfig importConfigconfig importConfig

app=Flask(__name__)=Flask(__name__)

app.config.from_object(Config).config.from_object(Config)

fromapp importroutesapp importroutes

Thoạt nhìn thì cách tham chiếu đến lớp Config có vẻ hơi khó hiểu. Nhưng nếu bạn quan sát kỹ thì nó cũng tương tự như cách chúng ta khai báo tham chiếu đến thực thể flask trong thư viện Flask mà chúng ta đã làm qua trước đây (Xin lưu ý sự khác nhau giữa chữ “f” thường và “F” hoa trong tên flask đại diện cho các đối tượng có ý nghĩa khác nhau). Ở đây, tên “config” (chữ thường) là tên của module config.py, còn tên “Config” là tên của lớp Config trong module config.py.

Như đã nói ở trên, các tham số cấu hình sẽ được truy cập qua từ điển trong app.config. Dưới đây là một ví dụ để lấy giá trị của khóa bí mật bằng trình biên dịch Python:

>>>frommyblog importappfrommyblog importapp

>>>app.config['SECRET_KEY']app.config['SECRET_KEY']

'khong-doan-noi-dau'

Thư viện mở rộng (Flask-WTF) sử dụng các lớp trong Python để đại diện cho các Web form. Các lớp này – gọi tắt là lớp form) sẽ định nghĩa các trường (field) có trên form qua các biến thành viên.

Theo đúng nguyên tắc phân chia các mối quan tâm đã được đề cập ở trên, chúng ta sẽ tạo ra một module mới trong thư mục app có tên là forms.py để chứa các thông tin về form đăng nhập của chúng ta. Chúng ta bắt đầu với một form đơn giản bao gồm hai khung nhập văn bản (text box) để người sử dụng có thể nhập vào tên người sử dụng và mật khẩu (username và password). Form này cũng có thêm một khung đánh dấu (checkbox) tên là “Remember me” và một nút bấm để gởi thông tin đăng nhập từ trình duyệt của người sử dụng về ứng dụng trên máy chủ (submit button).

app/forms.py: form đăng nhập form đăng nhập

fromflask_wtf importFlaskFormflask_wtf importFlaskForm

fromwtforms importStringField,PasswordField,BooleanField,SubmitFieldwtforms importStringField,PasswordField,BooleanField,SubmitField

fromwtforms.validators importDataRequiredwtforms.validators importDataRequired

classLoginForm(FlaskForm):LoginForm(FlaskForm):

    username=StringField('Username',validators=[DataRequired()])username=StringField('Username', validators=[DataRequired()])

    password=PasswordField('Password',validators=[DataRequired()])password=PasswordField('Password',validators=[DataRequired()])

    remember_me=BooleanField('Remember me')remember_me =BooleanField('Remember me')

    submit=SubmitField('Sign In')submit=SubmitField('Sign In')

Đa số các thư viện mở rộng của Flask dùng quy ước app.config0 để nhận dạng các tham chiếu đến chúng. Flask-WTF cũng không ngoại lệ và sử dụng tên tham chiếu là app.config1. Để sử dụng module app.config2 từ thư viện Flask-WTF, chúng ta khai báo như ở đầu của file app/forms.py

Ứng dụng của chúng ta cũng sử dụng bốn lớp khác từ gói WTForms để đại diện cho các trường nhập dữ liệu tương ứng. Mỗi một trường sẽ được đại diện bởi một biến trong lớp app.config3. Tham số đầu tiên khi khởi tạo mỗi trường sẽ là mô tả hoặc nhãn của chúng. Tham số tùy chọn app.config4 khi khởi tạo trường username và password cho phép chúng ta kiểm tra dữ liệu nhập. Biến kiểm tra (validator) app.config5 là một biến được định nghĩa bởi Flask-WTF cho phép ứng dụng kiểm tra và phát sinh thông báo lỗi nếu không có dữ liệu nhập trong trường tương ứng. Có nhiều kiểu biến kiểm tra khác nhau mà chúng ta sẽ tìm hiều về sau.

Template cho Form

Bước tiếp theo là tạo một HTML template sử dụng form của chúng ta. Việc tạo template này không quá phức tạp vì các trường được định nghĩa trong lớp LoginForm biết cách để tạo ra mã HTML cho chính chúng. Sau đây là đoạn mã để tạo ra template đăng nhập, chúng ta sẽ đặt mã này vào file app/templates/login.html:

app/templates/login.html: template cho form đăng nhập template cho form đăng nhập

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

{%extends"base.html"%}%extends"base.html"%}

{%blockcontent%}%blockcontent%}

& nbsp; & nbsp; & nbsp; & nbsp; đăng nhập

Sign In

    

action="" method="post"novalidate>

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & Nbsp;

        

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

        

        

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

        

& NBSP; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

{{ form.remember_me() }} {{ form.remember_me.label }}

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & Nbsp;

{{ form.submit() }}

    

{%endblock%}%endblock%}

Mẫu trong nÀy chún ta sẽ sử dụng lại mẫu cơ sở.html ĐượC GIớI THIệU TRONG PHầN 2 BằNG C ấu cấu trúc này Cho tất cả cau mẫu MớI

Mẫu NÀY Cần Có Một Tham Số Là MộT Th Tham Số NÀY CầN ĐượC TRUYềN Từ HÀM HIểN Th

Thẻ html app.config8 trong Đoạn mà trên thực tế không phải chỉ là một thẻ html, nó là một vật chứa (container) Thuộc Tính app.config9 Của Form Dùn Đấng ôn Nếu chadang ta gán một chuỗi trống cho thurộc tínH này thì theo mặc um Thuộc tính Config0 Phương thức mặc GịNH là gởi yêu cầu Theo dạng ____ Liệu bên trong g năm dữ liệu của yêu cầu http trong khi ____ yêu cầu, nhận, đăng bài, bạn nên Tham Khảo Trênn Wikipedia). Thuộc tính Config5 Dùng Để Thôn Bái v ới trình Duyệt Không Kiểm Tra Dữ Liệu Của Các Ệc DAng THUộC TínH ____ tìm hiểu ở phần Sau của bài nào.

Tham Số Config7 Sẽ TạO ra Một Trường ẩn (trường ẩn) Tất Nếu chún ta thực hiện Đủ các Điều kiện nào, flask-wtf đủ Thôn

Nếu bạn Đạo từng viết Html Web Form, Có Thể BạN Sẽ Th Lý do là vì Đối tượng hình thức mà chún ta khai báio trong forms. Việc chún ta cần lào là Nếu đó là trường nào cần bạn thne nh ững thu Ví dụ như khi bạn khởi tạo các Đối tượng tên người dùng và mật khẩu, bạn bạn thể thênm vào Thams số SECRET_KEY2 Đây Cũng là Cách Để Bạn Có Thể Chỉ Đ-NH Các

Hiển thị Form

Chún ta đã lào hầu hết các bước Để tạo ra mẫu ĐĂng NHập (đăng nhập). TUy Nhiênn, Để Hiển thị Form nÀy trong trình diyệt, chúnt ta Khi bạn Chúnt ta

app/routes.py: Hàm hiển thị cho form Login Hàm hiển thị cho form Login

fromflask importrender_templateflask importrender_template

fromapp importappapp importapp

fromapp.forms importLoginFormapp.forms importLoginForm

.....

@app.route('/login')app.route('/login')

deflogin():login():

    form=LoginForm()form=LoginForm()

    returnrender_template('login.html',title='Sign In',form=form)returnrender_template('login.html',title='Sign In', form=form)

Ở đây, chúng ta thêm tham chiếu đến lớp app.config3 từ module forms.py, khởi tạo một đối tượng từ lớp này và truyền đối tượng này vào template login.html bằng cách gọi hàm SECRET_KEY7. Đừng ngạc nhiên với tham số cuối cùng khi gọi hàm (SECRET_KEY8), thật ra nó chỉ đơn giản là truyền đối tượng SECRET_KEY9 mà chúng ta tạo ra từ lớp app.config3 trong dòng mã ở trên và truyền nó vào một Web form có tên là SECRET_KEY9 (được định nghĩa trong template login.html). Tất cả chỉ có vậy, chúng ta đã thành công trong việc liên kết form mà chúng ta tạo ra bằng mã Python với template theo định dạng của Jinja2. Flask sẽ làm phần còn lại.

Để giúp cho việc truy cập form Login dễ dàng hơn, chúng ta sẽ thay đổi một chút thanh định hướng ở template base.html:

app/templates/base.html: Liên kết đến trang Login trong thanh định hướng: Liên kết đến trang Login trong thanh định hướng:

    Myblog:

    Homehref="/index">Home

    Loginhref="/login">Login

Đến đây, bạn có thể chạy thử ứng dụng một lần nữa và kiểm tra form mà chúng ta đã tạo ra.  Sau khi ứng dụng được kích hoạt, hãy nhập địa chỉ SECRET_KEY2 vào trình duyệt và bấm vào liên kết “Login” trên thanh định hướng để truy nhập trang Login. Bạn thấy thế nào?

Hướng dẫn python web form builder - trình tạo biểu mẫu web python

Nhận dữ liệu từ form

Đến đây, chúng ta đã có một form đăng nhập thật hấp dẫn. Tuy nhiên, nếu bạn thử bấm vào nút “Sign in”, chúng ta sẽ thấy một thông báo lỗi không mấy dễ chịu: “Method Not Allowed”. Chuyện gì xảy ra ở đây? Lý do là vì hàm hiển thị của chúng ta mới chỉ làm có một nửa chuyện mà nó cần làm: nó hiển thị form nhưng hoàn toàn không có mã lệnh nào để làm công việc xử lý dữ liệu nhận được khi người dùng bấm nút gởi (submit) dữ liệu – nút “Sign in” trên form của chúng ta. Tiếp theo, chúng ta sẽ cập nhật hàm hiển thị để nhận và kiểm tra dữ liệu do người sử dụng nhập vào form như sau:

app/routes.py: Nhận thông tin người sử dụng Nhận thông tin người sử dụng

fromflask importrender_template,flash,redirectflask importrender_template,flash,redirect

@app.route('/login',methods=['GET','POST'])app.route('/login',methods=['GET','POST'])

deflogin(): login():

    form=LoginForm()form=LoginForm()

    ifform.validate_on_submit():ifform.validate_on_submit():

        flash('Yeu cau dang nhap tu user {}, remember_me={}'.format(flash('Yeu cau dang nhap tu user {}, remember_me={}'.format(

            form.username.data,form.remember_me.data))form.username.data,form.remember_me.data))

        returnredirect('/index')return redirect('/index')

    returnrender_template('login.html',title='Sign In',form=form)returnrender_template('login.html',title='Sign In',form=form)

Ở đây, chúng ta thêm tham chiếu đến lớp app.config3 từ module forms.py, khởi tạo một đối tượng từ lớp này và truyền đối tượng này vào template login.html bằng cách gọi hàm SECRET_KEY7. Đừng ngạc nhiên với tham số cuối cùng khi gọi hàm (SECRET_KEY8), thật ra nó chỉ đơn giản là truyền đối tượng SECRET_KEY9 mà chúng ta tạo ra từ lớp app.config3 trong dòng mã ở trên và truyền nó vào một Web form có tên là SECRET_KEY9 (được định nghĩa trong template login.html). Tất cả chỉ có vậy, chúng ta đã thành công trong việc liên kết form mà chúng ta tạo ra bằng mã Python với template theo định dạng của Jinja2. Flask sẽ làm phần còn lại.

Để giúp cho việc truy cập form Login dễ dàng hơn, chúng ta sẽ thay đổi một chút thanh định hướng ở template base.html:

app/templates/base.html: Liên kết đến trang Login trong thanh định hướng:Sign in”, trình duyệt sẽ gởi yêu cầu dưới dạng Config2 về máy chủ. Khi đó hàm app.config.from_object()5 sẽ tiến hành thu thập các dữ liệu từ các trường và chạy các đoạn mã kiểm tra dữ liệu. Nếu tất cả dữ liệu đều hợp lệ, hàm này sẽ trả về giá trị Config1 và cho phép ứng dụng bắt đầu xử lý dữ liệu. Nếu một trong các trường có dữ liệu không hợp lệ, hàm này sẽ trả về app.config.from_object()7 và do đó, sẽ hiển thị trang đăng nhập lần nữa tương tự như khi trình duyệt gởi yêu cầu dạng Config1. Sau này chúng ta sẽ thêm một thông báo lỗi và hiển thị cho người dùng nếu có dữ liệu không hợp lệ.

Tiếp theo, khi hàm app.config.from_object()5 trả về Config1, hàm hiển thị sẽ gọi hai hàm mới được tham chiếu từ Flask. HàmConfig6 sẽ giúp chúng ta hiển thị một thông điệp trên trang Web. Nhiều ứng dụng Web sử dụng kỹ thuật này để báo với người dùng các hoạt động tương tác của họ với ứng dụng có thành công hay không.Trong trường hợp này, chúng ta chỉ tạm thời sử dụng thông điệp để thông báo người dùng đã thành công đăng nhập vì chúng ta còn chưa có hệ thống quản lý và xác thực định danh của người dùng (chúng ta sẽ thêm phần này vào ứng dụng sau này). Hiện giờ, điều chúng ta có thể làm là hiển thị một thông điệp để xác nhận ứng dụng đã nhận được các thông tin của người dùng.

Hàm thứ nhì được gọi trong hàm hiển thị là Config7. Hàm này báo cho trình duyệt biết để tự động chuyển sang một trang khác. Địa chỉ của trang sẽ được chuyển đến là tham số được truyền vào hàm. Trong trường hợp này, thông số đó là Config8, vì vậy, ứng dụng sẽ tự động chuyển đến trang chủ nếu người dùng đăng nhập thành công.

Khi bạn gọi hàm Config9, Flask sẽ chứa thông điệp bạn truyền vào, nhưng thông điệp này sẽ không tự động hiển thị trên trang Web. Vì vậy, chúng ta cần thực hiện thêm một vài thao tác để hiển thị thông điệp này. Chúng ta sẽ thêm một số mã lệnh mới vào template base.html để nó được hiển thị trên mọi template được kế thừa từ template này. Sau đây là template base.html đã được cập nhật:

app/templates/base.html: Hiển thị thông điệp được truyền vào hàm flash() Hiển thị thông điệp được truyền vào hàm flash()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

    

        {% if title %}

        {{ title }} - Myblog</span><span>{{ title }} - Myblog</span><span>

        {% else %}

        Myblog</span><span>Myblog</span><span>

        {% endif %}

    

    

        

            Myblog:

            Homehref="/index">Home

            Loginhref="/login">Login

        

        


        {% with messages = get_flashed_messages() %}

        {% if messages %}

        

                {% for message in messages %}

                {{ message }}

  • {{ message }}
  •             {% endfor %}

            

        {% endif %}

        {% with messages = get_flashed_messages() %}

        {% if messages %}

    

        {% if title %}

        {{ title }} - Myblog

        {% else %}Sign in” để gởi dữ liệu về máy chủ nhưng chừa trống trường “username” hoặc “password”, làm như vậy bạn sẽ thấy cách hoạt động của các biến kiểm tra dữ liệu app.config5 – Chương trình sẽ báo lỗi và bạn sẽ không thể gởi dữ liệu (submit) được.

        {% endif %}

        {% with messages = get_flashed_messages() %}

Nếu bạn cố submit dữ liệu không hợp lệ với form login của chúng ta, có lẽ bạn sẽ để ý thấy rằng dù form hoạt động đúng theo ý đồ của chúng ta (hiển thị lại form với các dữ liệu nhập để bạn sửa đổi), nhưng không có gợi ý gì trên form để cho bạn biết dữ liệu nào sai hoặc thiếu và cần được sửa đổi. Vì vậy chúng ta có thể cải tiến mã của chúng ta để đưa ra các thông báo lỗi thích hợp và giúp cho người dùng dễ dàng nhận ra dữ liệu không hợp lệ.

Thật ra thì khi có dữ liệu không hợp lệ, các biến kiểm tra dữ liệu đã sinh ra các thông báo lỗi rồi, điều chúng ta cần làm là thêm một vài dòng lệnh để hiển thị các thông báo lỗi này mà thời.

Sau đây là phiên bản mới của template login với các thông báo lỗi cho các trường username và password:

app/templates/login.html: Thông báo lỗi nhập liệu trong template Login Thông báo lỗi nhập liệu trong template Login

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

{%extends"base.html"%}%extends"base.html"%}

{%blockcontent%}%blockcontent%}

    Sign In

Sign In

    

action="" method="post"novalidate>

        {{ form.hidden_tag() }}

        

            {{ form.username.label }}

            {{ form.username(size=32) }}

            {% for error in form.username.errors %}

            [{{ error }}]style="color: red;">[{{ error }}]

            {% endfor %}

        

        

            {{ form.password.label }}

            {{ form.password(size=32) }}

            {% for error in form.password.errors %}

            [{{ error }}]style="color: red;">[{{ error }}]

            {% endfor %}

        

            {{ form.password.label }}

{{ form.remember_me() }} {{ form.remember_me.label }}

            {{ form.password(size=32) }}

{{ form.submit() }}

    

{%endblock%}%endblock%}

            {% for error in form.password.errors %}

Hướng dẫn python web form builder - trình tạo biểu mẫu web python

        {{ form.remember_me() }} {{ form.remember_me.label }}

        {{ form.submit() }}

    

        Myblog:

        Homehref="/index">Home

        Loginhref="/login">Login

    

Thay đổi duy nhất mà chúng ta đã làm ở đây là thêm một vòng lặp ngay sau mã cho các trường username và password để hiển thị các thông báo lỗi sinh ra bởi biến kiểm tra bằng màu đỏ. Theo quy ước, các thông báo lỗi cho các trường có liên kết với biến kiểm tra dữ liệu sẽ được thêm vào biến Flask1. Biến errors sẽ là một danh sách (list) vì mỗi trường có thể liên kết với nhiều biến kiểm tra dữ liệu khác nhau và có khả năng sinh ra nhiều lỗi đồng thời. Sau khi bạn cập nhật template login.html, nếu bạn thử submit form mà không nhập username hoặc password, bạn sẽ thấy các thông báo lỗi màu đỏ.

@app.route('/login',methods=['GET','POST'])app.route('/login',methods=['GET','POST'])

deflogin():login():

    form=LoginForm()form= LoginForm()

    ifform.validate_on_submit():ifform.validate_on_submit():

        ......

        returnredirect('/index')return redirect('/index')

    ......

Tạo liên kết (link)

Đến đây thì form login gần như hoàn tất. Nhưng trước khi kết thúc phần này, chúng ta sẽ nói qua một chút về cách đặt các liên kết (link) và chuyển trang (redirect). Cho đến giờ, bạn đã thấy một số trường hợp chúng ta đặt các liên kết vào ứng dụng. Ví dụ như trong thanh định hướng ở template base.html:

Hàm hiển thị cho trang login cũng có một liên kết dưới dạng tham số cho hàm Config7:

Vì thế, từ bây giờ chúng ta sẽ tập làm quen bằng cách sử dụng hàm Flask3 mỗi khi chúng ta cần tạo ra các địa chỉ (hay liên kết – URL) cho ứng dụng. Theo đó, mã cho thanh định hướng trong template base.html sẽ được sửa lại như sau:

app/templates/base.html: Sử dụng hàm Flask3 để tạo các liên kết Sử dụng hàm Flask3 để tạo các liên kết

    

        Myblog:

        Homehref="{{ url_for('index') }}">Home

        Loginhref="{{ url_for('login') }}">Login

    

Và cuối cùng là hàm hiển thị login() sử dụng hàm url_for:

app/routes.py: Sử dụng hàm Flask3 để tạo các liên kết Sử dụng hàm Flask3 để tạo các liên kết

fromflask importrender_template,flash,redirect,url_forflask importrender_template,flash,redirect,url_for

# ...

@app.route('/login',methods=['GET','POST'])app.route('/login', methods=['GET','POST'])

deflogin():login():

    form=LoginForm()form=LoginForm()

    ifform.validate_on_submit():if form.validate_on_submit():

        ......

        returnredirect(url_for('index'))returnredirect(url_for('index'))

    ......

Đến đây, chúng ta có thể chạy thử lần nữa và lần này, bạn hãy thử nhập vào đầy đủ username, password và sau cùng, bấm nút “Sign In“. Bạn sẽ thấy kết quả tương tự như sau:Sign In“. Bạn sẽ thấy kết quả tương tự như sau:

Hướng dẫn python web form builder - trình tạo biểu mẫu web python

Xin chúc mừng, bạn đã thành công tạo ra form đăng nhập đầu tiên.

Chúng ta sẽ kết thúc ở đây, hẹn gặp lại bạn trong phần tiếp theo.