Web Server Development

Trong phần này chúng ta sẽ tìm hiểu về một thành phần khác đó là web server. Nội dung của phần chỉ đề cập đến vấn đề cơ bản, để tìm hiểu sâu hơn bạn có thể tham khảo Phát triển Website quản lý nội dung CMS.

Việc xử lý tất cả yêu cầu của web đều được điều khiển bởi thư viện werkzeug của Python.

Trong phần này, chúng ta sẽ tìm hiểu những nội dung sau:

  • Tạo một đường dẫn có thể truy cập

  • Hạn chế quyền truy cập vào các đường dẫn

  • Xử lý các tham số được truyền vào

  • Sửa đổi một trình xử lý hiện có

  • Cung cấp dữ liệu tĩnh

Tạo một đường dẫn có thể truy cập

Chúng ta sẽ tạo một đường dẫn URL có dạng http://your-server-url:8069/path1/path2 để người dùng có thể truy cập. Đường dẫn này có thể là một trang web hoặc trả về dữ liệu để người dùng có thể sử dụng cho các ứng dụng khác. Trong các trường hợp sau, bạn thường sử dụng định dạng JSON để sử dụng các tham số và cung cấp dữ liệu của mình.

Sẵn sàng

Cụ thể chúng ta sẽ tạo ra một module mới với tên là my_course, module sẽ hỗ trợ lấy thông tin của các khoá học trong model education.course. Chúng ta muốn bất cứ người dùng nào cũng có thể truy vấn để lấy thông tin của khoá học. Hơn nữa, chúng ta cũng có thể cung cấp thông tin như vậy cho các yêu cầu dưới dạng JSON

Các bước thực hiện

Trong module my_course tạo thêm thư mục controllers, trong thư mục controllers tạo thêm file main.py với nội dung như sau:

from odoo import http
from odoo.http import request

class Main(http.Controller):
    @http.route('/my_course/courses', type='http', auth='none')
    def course(self):
        courses = request.env['education.course'].sudo().search([])
        html_result = '<html><body><ul>'
        for course in courses:
            html_result += "<li> %s </li>" % course.name
        html_result += '</ul></body></html>'
        return html_result

Đoạn code trên sẽ trả dữ liệu dạng web khi bạn truy cập vào đường dẫn http://your-server-url:8069/my_course/courses. Để trả ra dữ liệu kiểu JSON, bạn chỉ cần đổi tham số type từ http sang json.

@http.route('/my_course/courses/json', type='json', auth='none')
def courses_json(self):
    courses = request.env['education.course'].sudo().search([])
    return courses.read(['name'])

Tiếp theo bạn cần thêm vào file __init__.py trong thư mục controllers, trong file __init__.py cần khai báo file main.py vừa được tạo ở trên.

from . import main

Cuối cùng ban cần khai báo controllers vào file __init__.py của module my_course

from . import controllers

Khởi động lại server, truy cập với đường dẫn http://your-server-url:8069/my_course/courses. Bạn sẽ nhận được thông tin tên của các khoá học.

Để test dữ liệu trả dưới dạng JSON, bạn cần tạo một yêu cầu dưới dạng JSON theo cấu trúc sau:

curl -i -X POST -H "Content-Type: application/json" -d "{}" localhost:8069/my_course/courses/json

Chạy câu lệnh trên ở terminal, nếu bạn nhận được lỗi 404, có thể bạn có nhiều hơn một database trên instance của bạn. Trong trường hợp này để có thể xác định chính xác database mà server yêu cầu. Bạn cần thêm --db-filter='database của bạn'

Cơ chế hoạt động

Hai phần quan trọng ở đây là các controllers được kế thừa từ odoo.http.Controllers và phương pháp để hiển thị nội dung được xử lý bởi odoo.http.route. Được kế thừa từ odoo.http.Controllers, các controllers được đăng ký với hệ thống định tuyến (route) giống như cách các model được đăng ký và kế thừa từ odoo.models.Model.

Nói chung, để tránh trùng tên, tên đường dẫn nên gắn với chức năng mà bạn muốn thực hiện. Tất nhiên nếu bạn mở rộng một số chức năng có sẵn, bạn sẽ sử dụng tên đường dẫn có sẵn.

oddo.http.route

Route để cho hệ thống hiểu rằng có một phương thức có thể truy cập được trên web ngay từ đầu và tham số đầu tiên (/my_course/courses) xác định đường dẫn nào có thể truy cập. Thay vì một chuỗi bạn có thể chuyển một danh sách các chuỗi, trong trường hợp bạn sử dụng cùng một hàm để phân phát nhiều đường dẫn.

Tham số type có giá trị mặc định là http, tham số này sẽ xác định xem loại yêu cầu nào được phục vụ. Để chuyển đổi sang kiểu JSON bạn chỉ cần khai báo type='json'.

Tham số auth dùng để hạn chế quyền truy cập vào đường dẫn, chúng ta sẽ tìm hiểu sau.

Giá trị trả về

Việc xử lý các giá trị trả về được xác định bởi tham số type của route. Đối với type='http' chúng ta muốn giá trị trả về dưới dạng HTML, tuy nhiên hàm đầu tiên chỉ đơn giản trả về một chuỗi chứa nó. Để xử lý giá trị trả về, bạn có thể sử dụng hàm request.make_response(). Hàm này cho phép bạn kiểm soát các tiêu đề để gửi phản hồi. Vì vậy, để cho biết thời điểm trang của chúng ta được cập nhật lần cuối, chúng ta có thể thay đổi dòng cuối cùng (return html_result) trong hàm course() thành mã sau:

return request.make_response(
    html_result, headers=[
        ('Last-modified', email.utils.formatdate((
            fields.Datetime.from_string(
            request.env['education.course'].sudo().search([], order='write_date desc', limit=1)
            .write_date) - datetime.datetime(1970, 1, 1)).total_seconds(), usegmt=True))
        ])

Đoạn code này gửi tiêu đề được sửa đổi lần cuối cùng với HTML được tạo ra, cho trình duyệt biết khi nào danh sách được sửa lần cuối. Chúng ta có thể lấy thông tin cập nhật từ trường write_date của model education.course. Để đoạn code trên hoạt động, bạn cần thêm vào các thư viện sau ở đầu file main.py.

import email
import datetime
from odoo import fields

Bạn cũng có thể tạo đối tượng phản hổi của werkzeug một cách thủ công và trả lại đối tượng đó nhưng việc này không mang lại nhiều lợi ích.

Quan trọng

Tạo HTML theo cách thủ công là tốt cho mục đích trình bày, nhưng bạn không bao giờ nên làm điều này trong bản production. Luôn sử dụng các mẫu (tham khảo 'tạo hoặc sửa đổi mẫu - QWeb' trong Phát triển Web client, gọi hàm request.render() để xử lý dữ liệu trả ra.

Điều này sẽ cung cấp cho bạn bản địa hóa miễn phí và sẽ làm cho mã của bạn tốt hơn bằng cách tách logic nghiệp vụ khỏi lớp trình bày. Ngoài ra, các mẫu cung cấp cho bạn các chức năng để tách dữ liệu trước khi xuất ra HTML. Đoạn mã trước đó dễ bị tấn công theo tập lệnh trên nhiều trang web (ví dụ: nếu người dùng quản lý để đưa thẻ tập lệnh vào tên khoá học).

Đối với một yêu cầu JSON, chỉ cần trả lại cấu trúc dữ liệu bạn muốn chuyển giao cho máy khách. Để điều này hoạt động, bạn nên hạn chế các loại dữ liệu có thể tuần tự hóa JSON, thường là dictionary, list, string, float và integer.

odoo.http.request

Đối tượng request là một đối tượng tĩnh đề cập đến yêu cầu hiện đang được xử lý, request chứa mọi thứ bạn cần để thực hiện hành động. Khía cạnh quan trọng nhất ở đây là thuộc tính request.env, nó chứa một đối tượng môi trường giống như self.env cho các model. Môi trường này bị ràng buộc với người dùng hiện tại. Trong các ví dụ trước chúng ta đã sử dụng auth = 'none' nên không có người dùng hiện tại. Việc thiếu người dùng cũng là lý do tại sao chúng ta phải sudo() tất cả các lệnh gọi đến các phương thức model trong ví dụ trên.

Nếu bạn đã quen với việc phát triển web, bạn sẽ mong đợi việc xử lý phiên, điều này hoàn toàn chính xác. Sử dụng request.session cho một đối tượng OpenERPSessionrequest.session.sid để truy cập ID phiên. Để lưu trữ các giá trị phiên, chỉ cần coi request.session như một dictionary. Như ví dụ sau:

request.session['hello'] = 'world'
request.session.get('hello')

Quan trọng

Lưu ý rằng việc lưu trữ dữ liệu trong phiên không khác gì việc sử dụng các biến toàn cục. Chỉ sử dụng nó nếu bạn phải. Điều này thường xảy ra đối với các hành động được yêu cầu nhiều.

Còn nữa...

Route có thể có một số tham số bổ sung, để tùy chỉnh hành vi của nó hơn nữa. Theo mặc định, tất cả các phương thức HTTP đều được phép và hệ thống sẽ trộn các tham số được truyền vào. Sử dụng tham số method bạn có thể truyền vào phương thức, thường sẽ là một trong hai phương thức ['GET'] hoặc ['POST'].

Vì lý do bảo mật và quyền riêng tư, trình duyệt chặn AJAX và một số loại yêu cầu khác đến từ các tên miền khác với nơi tập lệnh được tải từ đó. Để cho phép các yêu cầu có nguồn gốc chéo hãy đặt tham số CORS thành *. Việc cài đặt trên sẽ cho phép các yêu cầu từ tất cả các nguồn khác. Nếu tham số này không được đặt (mặc định là không được đặt) thì tiêu đề Access-Control-Allow-Origin sẽ không được đặt, khiến cho trình duyệt sẽ ngăn chặn các yêu cầu. Trong ví dụ trên, chúng ta có thể muốn đặt nó trên /my_course/courses/json, để cho phép các yêu cầu được lấy từ các trang web khác truy cập vào danh sách của khoá học.

Theo mặc định, Odoo bảo vệ một số loại yêu cầu nhất định khỏi một cuộc tấn công được gọi là giả mạo yêu cầu trên nhiều trang web, bằng cách chuyển mã thông báo theo mọi yêu cầu. Nếu bạn muốn tắt tính năng đó, hãy đặt thông số csrf thành False, nhưng lưu ý rằng đây không phải là ý tưởng hay.

Hạn chế quyền truy cập vào các đường dẫn

Chúng ta sẽ tìm hiểu ba cơ chế xác thực mà hệ thống cung cấp cho việc xác định định tuyến (route). Chúng ta sẽ xác định các định tuyến với cơ chế xác thực khác nhau từ đó chỉ ra sự khác biệt của chúng.

Sẵn sàng

Chúng ta sẽ tiếp tục với ví dụ lấy ra danh sách các khoá học.

Các bước thực hiện

Xác định các trình xử lý trong controllers/main.py

  1. Thêm một đường dẫn để đưa ra danh sách tất cả các khoá học. Đoạn code sau sẽ thực hiện điều đó.

@http.route('/my_course/all-courses', type='http', auth='none')
def all_courses(self):
    courses = request.env['education.course'].sudo().search([])
    html_result = '<html><body><ul>'
    for course in courses:
        html_result += "<li> %s </li>" % course.name
    html_result += '</ul></body></html>'
    return html_result
  1. Thêm một đường dẫn để đưa ra danh sách tất cả các khoá học và đánh dấu những khoá học được tạo bởi tài khoản hiện tại. Đoạn code sau sẽ thực hiện điều đó.

@http.route('/my_course/all-courses/course-mine', type='http', auth='public')
def all_courses_mark(self):
    courses = request.env['education.course'].sudo().search([])
    html_result = '<html><body><ul>'
    for course in courses:
        if request.env.user.id == course.create_uid:
            html_result += "<li> <b>%s</b> </li>" % course.name
        else:
            html_result += "<li> %s </li>" % course.name
    html_result += '</ul></body></html>'
    return html_result
  1. Thêm một đường dẫn để đưa ra danh sách của tất cả các khoá học được tạo bởi user hiện tại. Đoạn code sau sẽ thực hiện điều đó.

@http.route('/my_course/all-courses/mine', type='http', auth='user')
def all_courses_mine(self):
    courses = request.env['education.course'].search([ ('create_uid', '=', request.env.user.id), ])
    html_result = '<html><body><ul>'
    for course in courses:
        html_result += "<li> %s </li>" % courses.name
    html_result += '</ul></body></html>'
    return html_result

Đối với đường dẫn /my_course/all-courses/my_course/all-courses/course-mine không cần xác thực tài khoản, có thể xem được danh sách khoá học. Trong khi người dùng đã xác thực, các khoá học mà họ đã tạo sẽ được bôi đậm.

Đối với đường dẫn /my_course/all-courses/mine người dùng hoàn toàn không thể truy cập nếu như chưa xác thực tài khoản, nếu cố gắng truy cập sẽ bị điều hướng về trang đăng nhập.

Cơ chế hoạt động

Sự khác biệt giữa các phương pháp xác thực về cơ bản là những gì bạn có thể mong đợi từ nội dung của request.env.user.

Đối với auth = 'none', bản ghi người dùng luôn trống, ngay cả khi người dùng được xác thực đang truy cập đường dẫn. Sử dụng điều này nếu bạn muốn cung cấp nội dung không phụ thuộc vào người dùng.

Giá trị auth = 'public' đặt bản ghi người dùng thành một người dùng đặc biệt có ID XML của base.public_user cho những người dùng chưa được xác thực và vào hồ sơ của người dùng cho những người đã được xác thực. Đây là lựa chọn phù hợp nếu bạn muốn cung cấp chức năng cho cả người dùng chưa được xác thực và người dùng đã xác thực, trong khi những người đã xác thực có thêm một số tính năng.

Sử dụng auth = 'user' để đảm bảo rằng chỉ những người dùng được xác thực mới có quyền truy cập vào những gì bạn phải cung cấp. Với phương pháp này, bạn có thể chắc chắn rằng request.env.user trỏ đến một người dùng hiện có.

Thêm nữa...

Phương pháp xác thực xảy ra trong model ir.http từ phần bổ trợ cơ sở. Đối với bất kỳ giá trị nào bạn truyền cho tham số auth trong định tuyến của mình, Odoo sẽ tìm kiếm một hàm có tên _auth_method_<yourvalue> trên model này, vì vậy bạn có thể dễ dàng tùy chỉnh nó bằng cách kế thừa nó và khai báo một phương thức xử lý phương pháp xác thực mà bạn đã chọn.

Ví dụ: chúng tôi sẽ cung cấp một phương thức xác thực được gọi là group_teacher, phương thức này sẽ chỉ cấp quyền cho người dùng nếu người dùng hiện đang đăng nhập thuộc nhóm group_teacher, như được hiển thị trong ví dụ sau:

from odoo import exceptions, http, models
from odoo.http import request
class IrHttp(models.Model):
    _inherit = 'ir.http'
    def _auth_method_group_teacher(self):
        self._auth_method_user()
        if not request.env.user.has_group('group_teacher'):
        raise exceptions.AccessDenied()

Bây giờ bạn chỉ cần khai báo auth = 'group_teacher' trong định tuyến, nếu tài khoản đăng nhập thuộc group group_teacher tài khoản sẽ được xác thực với định tuyến.

Xử lý các tham số được truyền vào

Trong phần này chúng ta sẽ truyền vào tham số, dữ liệu trả ra sẽ phụ thuộc vào tham số được truyền vào. Ví dụ sau chúng ra sẽ truyền vào id của khoá học, thông tin của khoá học với id được truyền vào sẽ hiển thị.

Các bước thực hiện

Đầu tiên chúng ta sẽ thêm vào một định tuyến, định tuyến này sẽ yêu cầu tham số course_id để hiển thị thông tin chi tiết của khoá học. Sau đó chúng ta cũng làm như vậy nhưng tham số sẽ được kết hợp với chính đường dẫn của định tuyến.

  1. Thêm một đường dẫn với id của khoá học như là một tham số:

@http.route('/my_course/course_details', type='http', auth='none')
def course_details(self, course_id):
    record = request.env['education.course'].sudo().browse(int(course_id))
    html_result = '<html><body>'
    html_result += <h1>record.name</h1>
    html_result += <h1>record.description</h1>
    html_result += <h1>record.content</h1>
    html_result += '</body></html>'

    return html_result
  1. Thêm một đường dẫn mà chúng ta có thể truyền id của khoá học vào đường dẫn:

@http.route("/my_course/course_details/<model('education.course'):course>", type='http', auth='none')
def course_details_in_path(self, course):
    return self.course_details(course.id)

Nếu bạn truy cập vào đường dẫn http://your-server-url:8069/my_course/course_details?course_id=1 bạn sẽ xem được chi tiết của khoá học có id bằng 1. Nếu id này không tồn tại, bạn sẽ nhận được một trang lỗi. Nếu bạn truy cập đường dẫn http://your-server-url:8069/my_course/course_details/1 bạn sẽ nhận được nội dung tương tự.

Cơ chế hoạt động

Theo mặc định, werkzeug trộn các tham số GETPOST và chuyển chúng dưới dạng đối số từ khóa cho trình xử lý của bạn. Vì vậy, trong hàm của bạn bạn chỉ cần khai báo tham số course_id, bạn sẽ truyền tham số này vào dưới dạng GET (tham số trong URL) hoặc POST (thường được truyền dưới dạng form). Vì chúng ta đã không thêm giá trị mặc định cho tham số này, nên khi chạy sẽ phát sinh lỗi nếu bạn cố gắng truy cập vào đường dẫn này mà không đặt tham số.

Ví dụ thứ hai sử dụng thực tế là trong môi trường werkzeug, hầu hết các đường dẫn đều là ảo. Vì vậy, chúng ta có thể đơn giản xác định đường dẫn của mình là chứa một số đầu vào. Trong trường hợp này, chúng tôi nói rằng chúng tôi mong đợi id của một course là thành phần cuối cùng của đường dẫn. Tên sau dấu hai chấm là tên của đối số từ khóa. Hàm của chúng ta sẽ được gọi với tham số này được truyền dưới dạng đối số từ khóa. Ở đây, hệ thống sẽ lo việc tra cứu ID này và cung cấp một bản ghi duyệt, tất nhiên, bản ghi này chỉ hoạt động nếu người dùng truy cập vào đường dẫn này có quyền thích hợp. Cho rằng khoá học đó là một bản ghi duyệt, chúng ta có thể chỉ cần tái chế lại hàm của ví dụ đầu tiên bằng cách chuyển course.id làm tham số course_id, để đưa ra cùng một nội dung.

Còn nữa ...

Xác định các tham số trong đường dẫn là một chức năng được cung cấp bởi werkzeug, chức năng này được gọi là bộ chuyển đổi converters. Model converter được thêm bởi hệ thống, đồng thời hệ thống cũng thêm vào các model converter có thể chuyển đổi danh sách các id được phân cách nhau bởi dấu phẩy và chuyển danh sách này cho trình xử lý của bạn.

Cái hay của bộ chuyển đổi là ép buộc các kiểu tham số thành kiểu mong đợi, trong khi bạn sử dụng các tham số từ khoá bình thường. Chúng được phân phối dưới dạng chuỗi và bạn phải tự mình thực hiện các chuyển đổi cần thiết.

Các bộ chuyển đổi werkzeug được tích hợp sẵn bao gồm int, float và string, nhưng cũng có những biến phức tạp hơn, chẳng hạn như path, uuid. Bạn có thể tra cứu ý nghĩa của chúng tại werkzeug

Sửa đổi một trình xử lý hiện có

Khi cài đặt module website, đường dẫn /website/info hiển thị một vài thông tin của Odoo instance. Trong phần này chúng ta sẽ mở rộng một số thông tin hiển thị.

Sẵn sàng

Cài đặt module website và truy cập vào đường dẫn /website/info. Trong phần này chúng ta sẽ cập nhật định tuyến /website/info để cung cấp thêm nhiều thông tin.

Các bước thực hiện

Chúng ta sẽ phải điều chỉnh mẫu hiện có và ghi thêm thông tin về các app đã được cài đặt trên hệ thống. Chúng ta có thể làm điều này như sau:

  1. Mở rộng mẫu qweb trong tệp views/templates.xml, như sau:

 <?xml version="1.0" encoding="UTF-8"?>
 <odoo>
     <template id="show_website_info" inherit_id="website.show_website_info">
         <xpath expr="//dl[@t-foreach='apps']" position="after">
             <table class="table">
                 <tr t-foreach="apps" t-as="app">
                     <th>
                         <a t-att-href="app.website"><t t-esc="app.name" /></a>
                     </th>
                     <td><t t-esc="app.summary" /></td>
                 </tr>
             </table>
        </xpath>
    </template>
</odoo>
  1. Mở rộng trình xử lý trong file controllers/main.py như sau:

from odoo import http
from odoo.addons.website.controllers.main import Website

class WebsiteInfo(Website): @http.route()
def website_info(self):
    result = super(WebsiteInfo, self).website_info()
    result.qcontext['apps'] = result.qcontext['apps'].filtered(lambda x: x.name != 'website')
    return result

Bây giờ, khi truy cập trang thông tin, chúng ta sẽ thấy hiển thị thêm danh sách các ứng dụng đã cài đặt trong một bảng

Cơ chế hoạt động

Trong bước đầu tiên, chúng ta mở rộng một mẫu QWeb hiện có. Để tìm ra nó là cái nào, bạn sẽ phải tham khảo mã của trình xử lý ban đầu. Thông thường, điều này sẽ cung cấp cho bạn một cái gì đó tương tự như dòng sau, cho bạn biết rằng bạn cần ghi đè template.name:

return request.render('template.name', values)

Trong trường hợp của chúng ta, trình xử lý đã sử dụng mẫu website_info, nhưng mẫu này ngay lập tức được mở rộng bởi mẫu khác website.show_website_info, vì vậy sẽ thuận tiện hơn khi mở rộng mẫu này. Ở đây, chúng tôi đã mở rộng danh sách định nghĩa hiển thị các ứng dụng đã cài đặt bằng một bảng. Để biết chi tiết về cách hoạt động của kế thừa QWeb, hãy tham khảo Phát triển Web client.

Để mở rộng phương thức của trình xử lý, chúng ta phải xác định class của trình xử lý, trong trường hợp này là odoo.addons.website.controllers.main.Website. Chúng ta cần nhập các class để có thể kế thừa từ nó. Bây giờ, chúng ta có thể mở rộng phương thức và thay đổi dữ liệu được truyền cho phản hồi. Lưu ý rằng những gì mà trình xử lý mở rộng để trả về ở đây là một đối tượng chứ không phải một chuỗi HTML như các ví dụ trước đã làm. Đối tượng này chứa một tham chiếu đến mẫu sẽ được sử dụng và các giá trị có thể truy cập vào mẫu, nhưng nó chỉ được đánh giá ở cuối yêu cầu.

Nói chung, có ba cách để thay đổi trình xử lý hiện có:

  • Nếu sử dụng mẫu QWeb, cách đơn giản nhất để thay đổi là ghi đè lên mẫu. Đây là sự lựa chọn phù hợp cho những thay đổi bố cục và những thay đổi logic nhỏ.

  • Các mẫu QWeb nhận được một ngữ cảnh được truyền vào, ngữ cảnh này có sẵn trong phản hồi dưới dạng thành viên qcontext. Đây thường là một dictionary mà bạn có thể thêm hoặc bớt các giá trị cho phù hợp với nhu cầu của mình.

  • Nếu trình xử lý nhận được các tham số, bạn cũng có thể xử lý trước các tham số đó, để trình xử lý mở rộng hoạt động theo cách bạn muốn.

Thêm nữa...

Như đã thấy trong phần trước, kế thừa với controllers hoạt động hơi khác so với kế thừa model; bạn thực sự cần một tham chiếu đến lớp cơ sở và sử dụng kế thừa Python trên nó.

Đừng quên trang trí trình xử lý mới của bạn với trình trang trí http.route; Odoo sử dụng nó như một điểm đánh dấu, cho các phương thức được tiếp xúc với lớp mạng. Nếu bạn bỏ qua trình trang trí, bạn thực sự làm cho đường dẫn của trình xử lý không thể truy cập được.

Trình trang trí http.route hoạt động tương tự như khai báo trường: mọi giá trị bạn không đặt sẽ được bắt nguồn từ trình trang trí của hàm bạn đang ghi đè, vì vậy chúng ta không phải lặp lại các giá trị mà chúng ta không muốn thay đổi.

Sau khi nhận được đối tượng phản hồi từ hàm bạn ghi đè, bạn có thể làm được nhiều việc hơn là chỉ thay đổi ngữ cảnh QWeb:

  • Bạn có thể thêm hoặc xóa tiêu đề HTTP bằng cách thao tác với response.headers.

  • Nếu bạn muốn hiển thị một mẫu hoàn toàn khác, bạn có thể ghi đè response.template.

  • Để phát hiện xem một phản hồi có dựa trên QWeb ngay từ đầu hay không, hãy truy vấn response.is_qweb.

  • Mã HTML có sẵn bằng cách gọi response.render().

Xem thêm

Chi tiết về các mẫu QWeb sẽ được trình bày trong Phát triển Web client

Cung cấp dữ liệu tĩnh

Các trang web chứa các dữ liệu tĩnh như ảnh, video, CSS... Trong phần này chúng ta sẽ học cách quản lý các dữ liệu tĩnh trong module.

Sẵn sàng

Chúng ta sẽ hiển thị một bức ảnh trên trang web, bạn cần chuẩn bị một bức ảnh, chúng ta sẽ tiếp tục với module my_course.

Các bước thực hiện

Làm theo các bước sau để hiển thị hình ảnh trên trang:

  1. Thêm hình ảnh của bạn vào thư mục /my_course/static/src/img.

  2. Xác định tuyến mới trong bộ điều khiển. Trong đoạn code, hãy thay thế URL hình ảnh bằng URL hình ảnh của bạn:

@http.route('/demo_page', type='http', auth='none')
def books(self):
    image_url = '/my_course/static/src/image/viindoo.png'
    html_result = """<html><body><img src="%s"/></body></html>""" % image_url
    return html_result

Khởi động lại server, cập nhật lại module. Truy cập /demo_page để xem hình ảnh của trang.

Cơ chế hoạt động

Tất cả các tệp được đặt trong thư mục /static được coi là dữ liệu tĩnh và có thể truy cập công khai. Trong ví dụ trên chúng ta đã đặt hình ảnh trong thư mục /static/src/img. Bạn có thể đặt dữ liệun tĩnh ở bất kỳ đâu trong thư mục tĩnh, nhưng cấu trúc thư mục được đề xuất dựa trên loại tệp:

  • /static/src/img thư mục lưu trữ ảnh.

  • /static/src/css thư mục lưu trữ tệp định dạng css.

  • /static/src/scss thư mục lưu trữ tệp định dạng scss.

  • /static/src/fonts thư mục lưu trữ tệp định dạng font.

  • /static/src/js thư mục lưu trữ tệp javascript.

  • /static/src/xml thư mục lưu trữ tệp định dạng xml.

  • /static/lib thư mục lưu trữ các thư viện ngoài.

Trong ví dụ trên, chúng ta đã hiển thị một bức ảnh trên trang web. Bạn có thể truy cập trực tiếp bức ảnh từ /my_school/static/src/img/viindoo.png.

Trong phần này chúng ta đã hiển thị dữ liệu tĩnh là một bức ảnh lên một trang web, đồng thời chúng ta cũng được đề xuất các thư mục cho các dữ liệu tĩnh khác nhau. Có nhiều cách đơn giản hơn để trình bày nội dung và dữ liệu tĩnh mà chúng ta sẽ xem trong phần tiếp theo.