(91) 350-9520 support@omarine.org M-F: 7 AM - 7 PM; Weekends: 9 AM - 5 PM

Lập trình Web: Python: Django: Xây dựng cửa hàng trực tuyến với Oscar-Paypal, phần 2

4. URLconf

Bạn soạn thảo myshop/urls.py với nội dung sau:

from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
from django.conf.urls.static import static
from django.contrib import admin
from oscar.app import application

urlpatterns = [
        url(r'^admin/', include(admin.site.urls)),
        url(r'^i18n/', include('django.conf.urls.i18n')),
]

urlpatterns += i18n_patterns(
        url(r'^', application.urls),
)

if settings.DEBUG:
        urlpatterns += static(settings.MEDIA_URL,
                                            document_root=settings.MEDIA_ROOT)

Oscar hiện tại (phiên bản 1.5.1) sử dụng Django 1.11.9. Hàm url() có chức năng tương tự hàm path() của Django 2.0. Khác nhau ở chỗ tham số đầu tiên của hàm url() nhận một biểu thức chính quy.
Mẫu URL của admin dùng cho mục đích phát triển. Trong Oscar, công việc quản trị được thực hiện bằng Oscar dashboard.
Mẫu i18n dùng cho đặt ngôn ngữ và hàm i18n_patterns() thêm tiền tố mã ngôn ngữ tới các mẫu URL đối số. Chi tiết như sau:
Hộp chọn ngôn ngữ là kết quả của một form mà có action như dưới đây:

action="{% url 'set_language' %}"

'set_language' là tên của một mẫu URL trong django.conf.urls.i18n, với URL là /i18n/setlang/. URL này dẫn tới view là hàm set_language() trong django.views.i18n. Hàm set_language() sử dụng hàm is_safe_url() để quyết định chuyển hướng tới một URL yêu cầu, hay quay trở lại một URL ấn định. Dạng của hàm is_safe_url() như sau:

is_safe_url(url, host=None, allowed_hosts=None, require_https=False)

Trong đó, tham số host được khuyến cáo là không sử dụng, thay vào đó sử dụng allowed_hosts.

Trước khi phân tích tiếp, chúng ta xem xét khái niệm URL an toàn. Một URL có dạng

<scheme>://<netloc>/<path>;<params>?<query>#<fragment>

Hàm is_safe_url() đánh giá về URL an toàn như sau:

  1. URL rỗng luôn là không an toàn.
  2. Một URL là an toàn nếu nó thỏa mãn đánh giá an toàn cho cả bản thân nó và phiên bản thay thế toàn bộ ‘\’ với ‘/’ của nó. Nếu không, là không an toàn.
  3. URL bắt đầu với ‘///’ là không an toàn.
  4. URL sai cú pháp là không an toàn. Ví dụ biểu diễn sai địa chỉ IPv6.
  5. URL có scheme mà không có netloc là không an toàn. Ví dụ http:///example.com.
  6. URL bắt đầu với kí tự điều khiển là không an toàn. Kí tự điều khiển là kí tự có hạng unicode bắt đầu với ‘C’. Ví dụ ‘\b’ có hạng unicode là ‘Cc’.
  7. URL không có scheme mà có netloc được coi như có scheme là http.
  8. https là scheme duy nhất có giá trị nếu yêu cầu https, nếu không http và https đều là scheme có giá trị.
  9. URL không có cả scheme và netloc, và không thuộc tất cả các trường hợp không an toàn kể trên là URL an toàn.
  10. URL có netloc thuộc tập host cho phép và có scheme có giá trị, và không thuộc tất cả các trường hợp không an toàn kể trên là URL an toàn.
  11. Các URL không thuộc tất cả các trường hợp an toàn kể trên là không an toàn.

Một số điểm cần lưu ý:

  • URL có netloc thuộc tập host cho phép và có scheme có giá trị chưa đủ điều kiện an toàn. Ví dụ https://www.example.com\path với tập host cho phép là { 'www.example.com' }. URL này có scheme hợp lệ và khi thay thế ‘\’ với ‘/’ nó có netloc là 'www.example.com' thỏa mãn thuộc tập host cho phép, nhưng giá trị nguyên bản của nó được đánh giá là không an toàn. Do đó đánh giá tổng hợp là không an toàn, rơi vào trường hợp thứ 2 trong danh sách trên.
    Ví dụ khác:
    http:///example.com rơi vào trường hợp thứ 5. Nó có scheme hợp lệ nếu https là không yêu cầu, nhưng không có netloc hay netloc của nó là xâu rỗng. Nếu tập host cho phép là { '' } thì URL này thỏa mãn có netloc thuộc tập host cho phép. Nhưng nó là URL không an toàn.
  • Hàm is_safe_url() được dùng chủ yếu để chuyển hướng và các scheme được đánh giá để an toàn truy xuất tài nguyên một cách tương đối, phụ thuộc vào yêu cầu bảo mật đặt ra. Khi có yêu cầu https, thì http trở thành schem không có giá trị. https không chỉ là giao thức bảo mật mà nó còn nâng hạng site trong các máy tìm kiếm, và một số ứng dụng Web yêu cầu https để hoạt động.

Bây giờ chúng ta quay lại hàm set_language(). Hàm này dùng để đặt ngôn ngữ từ người sử dụng, nó mong đợi một request dạng POST với tham số language đặt cho mã ngôn ngữ và tham số next dùng cho URL để chuyển hướng. Tuy vậy, vẫn có thể có request dạng GET đi tới, do đó hàm phải xử lý cả hai.
Request dạng GET là không mong đợi, cho nên hàm set_language() muốn người dùng quay lại một URL thích hợp. Nó dùng hàm is_safe_url() để kiểm tra URL lấy từ tham số next. Tập host cho phép được xác định sử dụng hàm get_host() của đối tượng request, như sau:

  • Nếu dự án cấu hình USE_X_FORWARDED_HOST và HTTP_X_FORWARDED_HOST có mặt trong các tiêu đề HTTP của request, lấy host gốc của request từ tiêu đề đó.
  • Nếu bước trên không đạt được, lấy host từ tiêu đề HTTP_HOST.
  • Nếu vẫn chưa đạt được, lấy host từ tiêu đề SERVER_NAME, bổ sung thêm số cổng.
  • host kết quả phải thuộc các host cho phép trong cấu hình dự án.

Yêu cầu https xác định theo scheme của request. Nếu scheme là https thì yêu cầu https, ngược lại là không yêu cầu.
Nếu next (gọi thay cho URL của tham số này, để chỉ URL chuyển hướng) là an toàn, hàm set_language() chuyển hướng tới đó. Nếu request dạng AJAX và next không được đặt, mã trạng thái 204 (không nội dung) được trả về. Các trường hợp còn lại hàm sẽ xử lý để chuyển hướng người dùng quay lại một URL thích hợp.
Nếu người sử dụng tới đây bằng cách nhấp chuột vào một link, next được gán với URL từ tiêu đề HTTP_REFERER. Nếu vẫn chưa an toàn, chuyển hướng đi tới ‘/’.
Ví dụ, nếu chúng ta đang sử dụng server phát triển và gõ vào trình duyệt:

http://localhost:8000/i18n/setlang/?next=https://www.example.com

Hàm set_language() sẽ được gọi và URL chuyển hướng là không an toàn vì netloc của nó là 'www.example.com' trong khi tập host cho phép là { 'localhost:8000' }. Chuyển hướng sẽ đi tới ‘/’, tức là về trang đầu. Chi tiết như sau:

Phương thức request: GET
Tập host cho phép: { 'localhost:8000' }
Yêu cầu https?: Không

URL chuyển hướng: https://www.example.com
Là URL an toàn?: Không

request dạng AJAX?: Không
Tiêu đề HTTP_REFERER: Trống
Đặt USE_X_FORWARDED_HOST?: Không

Tiêu đề HTTP_HOST: localhost:8000
Tiêu đề SERVER_NAME: localhost


Trên đây đã phân tích khi request trong dạng GET. Trong trường hợp là POST, hàm set_language() đặt ngôn ngữ trước khi chuyển hướng. Nó giữ mã ngôn ngữ vào phiên của người dùng hoặc cookie. Vì chúng ta đã cấu hình sử dụng phiên nên đặt ngôn ngữ sẽ được giữ trong phiên. URL chuyển hướng được qui định trong form của hộp chọn ngôn ngữ. Nó là một URL mà có đường dẫn tương tự trang trước, ngoại trừ không có tiền tố mã ngôn ngữ. Rồi hàm i18n_patterns() thêm tiền tố cho ngôn ngữ mới.

Còn một mục nữa cho URLconf là hàm static(). Hàm này được dùng trong khi phát triển, trả về mẫu URL cho các tệp upload. Chúng ta thay giá trị MEDIA_URL đã cấu hình để dễ theo dõi

urlpatterns += static('/media/', document_root=settings.MEDIA_ROOT)

Nội dung chính của hàm static() như sau:

import re
from django.urls import re_path
from django.views.static import serve
# ...

def static(prefix, view=serve, **kwargs):

    # ...
    return [
        re_path(r'^%s(?P<path>.*)$' % re.escape(prefix.lstrip('/')), view, kwargs=kwargs),
    ]

Hàm re_path() chính là hàm mà nhận url() làm bí danh. Mẫu URL trên có view là django.views.static.serve(). Cuộc gọi tới static() trong URLconf truyền 2 đối số: đối số vị trí ‘/media/’ và đối số từ khóa document_root=settings.MEDIA_ROOT.
Bên trong hàm static(), sau khi prefix đã bỏ hết ‘/’ bên trái, re.escape() thực hiện thoát tất cả các kí tự của nó trừ các kí tự ASCII, số và ‘_’. Kết quả là ‘media\/’. Thoát kí tự có tác dụng làm cho các kí tự của xâu trở lại nghĩa thông thường của chúng khi tham gia vào biểu thức chính quy, ví dụ đối với ‘.’. Tuy nhiên, đối với ‘/’ là không cần thiết, do đó chúng ta có biểu thức tương đương là ‘media/’. Mặt khác, kwargs là từ điển của đối số từ khóa document_root=settings.MEDIA_ROOT. Như vậy, mẫu URL khi dùng thực tế sẽ trở thành

re_path(r'^media/(?P<path>.*)$', serve, { 'document_root': settings.MEDIA_ROOT })

Xâu kí tự khớp URL là một biểu thức chính quy sử dụng một nhóm tên là path để khớp mọi đường dẫn đằng sau media/. Như thế, mọi tệp upload có URL với tiền tố /media/ đều khớp mẫu này. path được trích ra, cùng với đối số từ khóa lấy trong từ điển, để gửi tới view. Cuộc gọi tới hàm serve() sẽ như sau:

serve(request, path=path, document_root=settings.MEDIA_ROOT)

Hàm serve() rồi nối path vào document_root để tạo đường dẫn đầy đủ, mở tệp và trả về một đối tượng đáp ứng file FileResponse.

5. Tạo cơ sở dữ liệu

Oscar đã có sẵn các migration, bạn chỉ cần di chuyển chúng vào cơ sở dữ liệu:

python manage.py migrate

6. Chạy server

python manage.py runserver

Đổi ngôn ngữ thật dễ dàng:

Advertisements

Gửi phản hồi

Website này sử dụng Akismet để hạn chế spam. Tìm hiểu bình luận của bạn được duyệt như thế nào.

%d bloggers like this: