Hướng dẫn dùng flask parameters python
Trong phần này, chúng ta sẽ xây dựng chức năng gởi thông điệp cá nhân cũng như hiển thị các thông báo trên thanh định hướng mà không cần phải tải lại (refresh) nội dung trang Web từ máy chủ. Show Để 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:
Bạn có thể truy cập mã nguồn cho phần này tại GitHub. Chúng ta sẽ tiếp tục cải tiến trải nghiệm người sử dụng với ứng dụng Myblog bằng hệ thống thông báo (notification). Các ứng dụng xã hội dùng hệ thống thông báo để hiển thị các thông báo cho người dùng và cho họ biết rằng họ được nhắc đến hoặc nhận được các tin nhắn cá nhân từ những người sử dụng khác. Các thông báo này thường được trình bày dưới dạng một ô nhỏ với một con số trên thanh định hướng. Ngoài ra, hệ thống thôn báo còn được dùng trong những trường hợp khác để báo với người sử dụng những việc họ cần làm. Để minh họa cho tác dụng của hệ thống thông báo cũng như các kỹ thuật có liên quan để xây dựng nó, chúng ta sẽ tạo ra một chức năng có sử dụng hệ thống này. Trong phần tiếp theo, chúng ta sẽ xây dựng một hệ thống nhắn tin cho phép người sử dụng gởi tin nhắn cho nhau. Thật ra thì việc tạo ra chức năng nhắn tin không hề khó, và nó cũng giúp chúng ta ôn lại các khái niệm về Flask mà chúng ta đã tìm hiểu từ đầu của loạt bài này. Sau khi đã có hệ thống nhắn tin, chúng ta sẽ tham khảo một vài tùy chọn và xây dựng chức năng hiển thị số tin nhắn cho ứng dụng. Tin nhắn cá nhânChức năng nhắn tin cá nhân mà chúng ta sắp xây dựng sẽ rất đơn giản. Khi bạn đến thăm một trang hồ sơ cá nhân của một user nào đó, một liên kết để gởi một tin nhắn cá nhân cho user đó sẽ được hiển thị. Liên kết này sẽ dẫn bạn đến một trang web khác với form để gởi tin nhắn. Nếu bạn nhận được tin nhắn từ các user khác, thanh định hướng ở phía trên cùng của ứng dụng sẽ hiển thị liên kết “Message”. Liên kết này sẽ cho phép bạn truy nhập vào một trang Web có cấu trúc tương tự như trang chủ hay trang Explore, nhưng nó sẽ hiển thị các tin nhắn thay vì các bài viết. Phần tiếp theo sẽ trình bày các bước cần thiết để tạo chức năng này. Hỗ trợ cơ sở dữ liệu cho các tin nhắn cá nhânCông việc đầu tiên là mở rộng cơ sở dữ liệu để hỗ trợ cho các dữ liệu về tin nhắn. Sau đây là mô hình dữ liệu app/models.py: Mô hình dữ liệu cho tin nhắn
Mô hình dữ liệu này tương tự như mô hình dữ liệu app/models.py: Hỗ trợ tin nhắn cá nhân trong mô hình dữ liệu User
Hai quan hệ (relationship) được định nghĩa trong đoạn mã trên sẽ trả về các tin nhắn được gởi và nhận bởi một user, đồng thời thêm các tham chiếu hồi quy (back reference) là Đến đây, chúng ta đã hoàn thành các thay đổi trong cơ sở dữ liệu. Đã đến lúc chúng ta cần thực hiện việc chuyển đổi cơ sở dữ liệu theo các cập nhật này:
Gởi tin nhắn cá nhânTiếp theo, chúng ta cần một form đơn giản để user có thể nhập và gởi tin nhắn: app/main/forms.py: Lớp tạo form nhắn tin.
Chúng ta cũng cần một template HTML tương ứng với form trên để hiển thị nó: app/templates/send_message.html: Template HTML để gởi tin nhắn.
Chúng ta cũng cần tạo ra một định tuyến mới theo định dạng /send_message/ và hàm xử lý cho địa chỉ này để xử lý việc gởi tin nhắn: app/main/routes.py: Hàm xử lý và địa chỉ (Định tuyến) cho các tin nhắn cá nhân.
Đoạn mã trên tương đối rõ ràng, việc gởi tin nhắn cá nhân thực chất là lưu một thực thể Công việc cuối cùng để kết nối các công đoạn trên đây là thêm một liên kết đến địa chỉ trên vào trang hồ sơ cá nhân: app/templates/user.html: Liên kết đến trang gởi tin nhắn cá nhân từ trang hồ sơ cá nhân.
Đọc tin nhắn cá nhânPhần quan trọng thứ hai trong chức năng nhắn tin là làm thế nào để user có thể đọc các tin nhắn đã nhận được. Để làm điều này, chúng ta sẽ thêm một địa chỉ mới là /messages và được xử lý tương tự như trang chủ hoặc trang Explore, bao gồm cả chức năng phân trang: app/main/routes.py: Hàm hiển thị tin nhắn cá nhân.
Trong hàm này, đầu tiên chúng ta sẽ cập nhật trường Hàm hiển thị này sẽ hiển thị template /app/templates/messages.html dưới đây: app/templates/messages.html: Template HTML để đọc tin nhắn.
Ở đây, chúng ta sử dụng một mẹo nhỏ: bởi vì các thực thể Để user có thể truy cập trang tin nhắn, chúng ta sẽ tạo liên kết mới “Messages” trong thanh định hướng: app/templates/base.html: Liên kết đến trang tin nhắn trong thanh định hướng.
Đến đây, chúng ta đã hoàn tất chức năng nhắn tin. Tuy nhiên, trong quá trình xây dựng chức năng này, chúng ta đã thêm một số văn bản mới vào ứng dụng, vì vậy, để tiếp tục hỗ trợ đa ngôn ngữ, chúng ta cần cập nhật phần dịch thuật cho các văn bản này. Bước đầu tiên là cập nhật các file chỉ mục ngôn ngữ:
Sau đó, chúng ta sẽ cần cung cấp văn bản được dịch với các ngôn ngữ được hỗ trợ trong các file messages.po tương ứng nằm trong thư mục app/translation. Bạn có thể sử dụng file dịch thuật cho tiếng Việt tại GitHub cho phần này. HIện giờ, người sử dụng đã có thể sử dụng hệ thống nhắn tin mới để gởi tin nhắn lẫn nhau. Tuy nhiên, ứng dụng lại chưa thể thông báo với user khi họ nhận được tin nhắn. Để user có thể biết được khi nào họ có tin nhắn mới, chúng ta sẽ tạo một ô thông báo nhỏ trên thanh định hướng để hiển thị số tin nhắn mà user nhận được nhưng chưa đọc. Chúng ta sẽ sử dụng mẫu huy hiệu (badge) từ Bootstrap để tạo ô thông báo và đặt nó vào trong template gốc (base.html) của ứng dụng: app/templates/base.html: Ô hiển thị số tin nhắn trong thanh định hướng.
Ở đây chúng ta gọi trực tiếp phương thức Ô hiển thị thông báo độngGiải pháp chúng ta vừa thực hiện ở trên đơn giản và vừa đủ để hiển thị ô thông báo. Tuy vậy, nó bất tiện ở chỗ ô thông báo chỉ xuất hiện khi trang Web vừa được tải về từ server. Nếu user xem nội dung của trang trong một thời gian đủ dài và không bấm vào các liên kết, các tin nhắn mới trong suốt thời gian này sẽ không xuất hiện trên ô thông báo cho đến khi user bấm vào một liên kết vả tải về một trang mới. Để ô thông báo hữu ích hơn cho người sử dụng, chúng ta cần làm cho nó có khả năng cập nhật số tin nhắn chưa được đọc mà không cần người sử dụng phải tải lại trang. Một trở ngại trong giải pháp tĩnh hiện thời là ô thông báo chỉ được hiển thị khi số tin nhắn lớn hơn 0 khi trang được tải về. Do đó, chúng ta cần làm cho ô thông báo này luôn luôn nằm trong thanh định hướng nhưng sẽ được giấu đi khi số tin nhắn là 0, điều này sẽ giúp chúng ta dễ dàng hiển thị ô thông báo với JavaScript khi cần: app/templates/base.html: Ô thông báo “thân thiện” hơn với JavaScript.
Với phiên bản này, chúng ta luôn có ô thông báo trong mọi trang, nhưng thuộc tính CSS Tiếp theo, chúng ta có thể viết một đoạn mã JavaScript ngắn để cập nhật ô thông báo với một số mới: app/templates/base.html: Ô thông báo đã được điều chỉnh trong thanh định hướng.
Hàm Gởi thông báo đến người sử dụngPhần việc còn lại là xây dựng cơ chế để cập nhật số tin nhắn trên trình duyệt của người sử dụng theo định kỳ. Trong mỗi chu kỳ cập nhật, trình duyệt sẽ gọi hàm Có hai phương pháp để server có thể gởi các thông tin cần cập nhật đến trình duyệt của người sử dụng. Và cả hai phương pháp đều có ưu và khuyết điểm riêng. Vì vậy, việc chọn phương pháp nào tùy thuộc vào từng dự án. Trong phương pháp thứ nhất, trình duyệt sẽ định kỳ hỏi server về các thông tin cần được cập nhật bằng cách gởi một yêu cầu bất đồng bộ. Server sẽ trả lời cho yêu cầu này với một danh sách các thông tin cần được cập nhật. Nhờ các thông tin này, trình duyệt sẽ có thể cập nhật các phần tử trong trang như là ô thông báo. Phương pháp thứ hai cần sử dụng một kiểu kết nối đặc biệt giữa trình duyệt và server, cho phép server chủ động gởi các cập nhật đến trình duyệt khi cần. Lưu ý rằng dù sử dụng phương pháp nào, chúng ta đều nên xem các thông báo như là các thực thể tổng quát để có thể xây dựng cấu trúc này cho các sự kiện khác nhau ngoài thông báo số tin nhắn chưa được đọc. Ưu điểm lớn nhất của phương pháp thứ nhất là dễ thực hiện. Chúng ta chỉ cần thêm một định tuyến mới vào ứng dụng (ví dụ như /notifications) và trả về danh sách các thông báo theo dạng JSON. Ở trình duyệt, ứng dụng sẽ nhận danh sách này và tiến hành các công việc cần thiết để cập nhật trang hiện hành. Khuyết điểm của phương pháp này là sẽ có độ trễ giữa thời gian sự kiện xảy ra và khi người sử dụng nhận được thông báo về sự kiện bởi vì trình duyệt sẽ gởi yêu cầu cập nhật theo định kỳ (cụ thể là user sẽ không nhận được thông báo ngay khi có tin nhắn mới mà phải chờ đến chu kỳ cập nhật của ứng dụng). Ví dụ như nếu ứng dụng thiết lập cho trình duyệt gởi yêu cầu cập nhật mỗi 10 giây, thông báo có thể đến trễ 10 giây sau khi sự kiện đã xảy ra. Phương pháp thứ hai yêu cầu một số thay đổi ở mức độ giao thức bởi vì giao thức HTTP không có các phương tiện cần thiết để gởi dữ liệu đến trình duyệt khi không được yêu cầu. Cho đến nay, cách phổ biến nhất để khắc phục trở ngại này là mở rộng mã nguồn ứng dụng để hỗ trợ kết nối theo kiểu WebSocket. Không như HTTP, WebSocket cho phép tạo một liên kết cố định giữa server và trình duyệt. Nhờ đó, server và trình duyệt có thể gởi và nhận dữ liệu tại mọi thời điểm mà không cần được yêu cầu trước. Ưu điểm của phương pháp này là bất cứ khi nào một sự kiện có liên quan đến client xảy ra, server có thể gởi thông báo đến trình duyệt ngay lập tức mà không cần được trình duyệt yêu cầu trước. Khuyết điểm của phương pháp này cách xây dựng phức tạp hơn HTTP bởi vì server cần duy trì kết nối cố định đến mọi trình duyệt và các phần mềm khách khác. Hãy tưởng tượng một server với bốn worker có thể phục vụ cho hàng trăm máy khách sử dụng HTTP cùng lúc vì các kết nối HTTP không tồn tại quá lâu và thường xuyên được xoay vòng. Tuy nhiên, cùng một server như vậy chỉ có thể phục vụ bốn máy khách sử dụng kết nối WebSocket cùng lúc. Trong phần lớn các trường hợp, điều này không đủ đáp ứng nhu cầu sử dụng. Bởi vì hạn chế này nên các ứng dụng với WebSocket thường được thiết kế theo kiểu bất đồng bộ bởi vì phương pháp này hiệu quả hơn khi phải quản lý số lượng worker và kết nối lớn. Điều tốt là cả hai phương pháp đều cung cấp hàm gọi lại (callback function) để chúng ta có thể sử dụng ở trình duyệt khi nhận được danh sách các cập nhật từ server. Vì vậy, để đơn giản, chúng ta có thể bắt đầu với phương pháp thứ nhất, và sau đó chúng ta có thể thay đổi thành server sử dụng WebSocket nếu cần thiết. Thật ra thì đối với các ứng dụng theo kiểu của chúng ta, phương pháp thứ nhất đã là đủ để đáp ứng. Phương pháp sử dụng WebSocket chỉ cần thiết cho các ứng dụng yêu cầu độ trễ thấp. Trong trường hợp bạn muốn biết, Twitter cũng sử dụng phương pháp thứ nhất cho các thông báo trong thanh định hướng. Facebook sử dụng một biến thể của nó gọi là long polling để khắc phục một số giới hạn của việc gởi yêu cầu định kỳ với HTTP. StackOverflow và Trello sử dụng WebSocket cho các thông báo trong ứng dụng. Bạn có thể quan sát các hoạt động nền của các Web site bằng cách sử dụng thẻ Network trong công cụ phát triển của trình duyệt. Sau đây, chúng ta sẽ bắt đầu xây dựng giải pháp theo phương pháp thứ nhất. Đầu tiên, chúng ta cần thêm một mô hình dữ liệu mới để theo dõi số thông báo cho người sử dụng và kèm theo đó là quan hệ với mô hình dữ liệu User: app/models.py: Mô hình dữ liệu thông báo.
Một thông báo sẽ bao gồm tên, user sẽ nhận thông báo, mốc thời gian (timestamp) theo định dạng Unix và dữ liệu (payload). Giá trị mặc định của mốc thời gian sẽ được lấy từ hàm Với mô hình dữ liệu này, chúng ta cần cập nhật và chuyển đổi cơ sở dữ liệu:
Và cũng để thuận tiện, chúng ta sẽ thêm các mô hình dữ liệu mới là myblog.py: Thêm mô hình dữ liệu mới vào ngữ cảnh dòng lệnh.
Chúng ta cũng sẽ thêm hàm trợ giúp app/models.py: Mô hình dữ liệu User.
Phương thức này sẽ lưu một thông báo vào cơ sở dữ liệu và nếu có một thông báo cùng tên trong cơ sở dữ liệu, nó sẽ xóa thông báo có sẵn trước khi tiến hành lưu thông báo hiện tại. Thông báo chúng ta đang xây dựng sẽ được gọi là Mỗi khi có thay đổi về số tin nhắn chưa được đọc, chúng ta cần gọi hàm app/main/routes.py: Cập nhật thông báo cho user.
Nơi tiếp theo mà số tin nhắn chưa đọc sẽ được cập nhật là trong trang nhắn tin, khi user mở trang này, theo quy ước của chúng ta, số tin nhắn chưa đọc sẽ trở về 0: app/main/routes.py: Đọc các tin nhắn.
Sau khi đã các thông báo cho user được lưu vào cơ sở dữ liệu, chúng ta có thể thêm một địa chỉ mới và hàm xử lý tương ứng để trình duyệt có thể dùng để nhận các thông báo cho một user đã đăng nhập: app/main/routes.py: Hàm hiển thị cho các thông báo.
Đây là một hàm tương đối đơn giản và sẽ trả về dữ liệu là mọt danh sách các thông báo cho user theo định dạng JSON. Mỗi thông báo sẽ là một từ điển với ba phần tử: tên thông báo, các dữ liệu của thông báo (payload) như là số tin nhắn, và mốc thời gian (timestamp). Các thông báo sẽ được trả về theo thứ tự thời gian chúng đã được tạo ra, từ cũ nhất đến mới nhất. Chúng ta không muốn trả về các thông báo trùng lặp. Vì vậy, chúng ta sẽ cung cấp tùy chọn để client có
thể chỉ yêu cầu các thông báo từ một thời điểm được chọn. Tùy chọn Bước cuối cùng để hoàn thiện chức năng này là xây dụng mã nguồn ở phía client (trong trường hợp này là trình duyệt) để thực hiện việc gởi yêu cầu nhận thông báo đến server theo định kỳ (polling). Chúng ta sẽ đặt mã này vào trong template gốc để mọi trang trong ứng dụng đều có chức năng này: app/templates/base.html: Yêu cầu nhận thông báo từ server theo định kỳ.
Hàm này được đặt bên trong một điều kiện của template bởi vì chúng ta chỉ muốn thực hiện quá trình này cho các user đã đăng nhập. Các user không đăng nhập sẽ không sử dụng được chức năng này. Chúng ta đã sử dụng hàm Hàm được sử dụng với bộ đếm giờ sẽ gởi các yêu cầu Ajax đến server theo định kỳ. Khi nhận được hồi đáp từ server, nó sẽ duyệt qua danh sách các thông báo. Nếu nhận được thông báo với tên gọi Cách xử lý tham số Cách đơn giản nhất để thử nghiệm chức năng này là sử dụng hai trình duyệt khác nhau và đăng nhập vào Myblog từ mỗi trình duyệt với một user khác nhau. Sau đó, gởi một hoặc nhiều tin nhắn từ user trên trình duyệt đầu tiên đến user trên trình duyệt thứ hai. Thanh định hướng trên trình duyệt thứ hai sẽ hiển thị số tin nhắn bạn đã gởi trong vòng 10 giây. Và nếu bạn bấm vào liên kết đến trang Message, số tin nhắn được hiển thị trong thông báo sẽ trở về 0. Chúng ta sẽ tạm ngừng ở đây. Hẹn gặp bạn trong phần tiếp theo. |