Hệ thống định tuyến trong Django

Hệ thống định tuyến trong Django

Định tuyến là gì?

Tài liệu chính thức của Django 1.11 về cấu hình URL

Cấu hình URL (URLconf) giống như mục lục của website được xây dựng bằng Django. Bản chất của nó là bảng ánh xạ giữa URL và hàm view sẽ được gọi khi truy cập URL đó. Chúng ta sử dụng cơ chế này để thông báo cho Django biết rằng khi gặp URL cụ thể nào đó, hệ thống cần thực thi hàm tương ứng.
  • Định dạng cơ bản:
from django.conf.urls import url

urlpatterns = [
     url(biểu_thức_chính_quy, hàm_view, tham_số, biệt_danh),
]
"""
Biểu thức chính quy: chuỗi biểu thức chính quy
Hàm view: đối tượng có thể gọi, thường là một hàm view
Tham số: các tham số mặc định tùy chọn truyền cho hàm view (dưới dạng từ điển)
Biệt danh: tham số name tùy chọn
"""
  • Ví dụ:
# Cách viết cho Django 1.11
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^posts/2019/$', views.case_2019),      # Chỉ khớp với một trường hợp duy nhất, định tuyến tĩnh
    url(r'^posts/([0-9]{4})/$', views.year_archive), # Có thể khớp nhiều trường hợp, định tuyến động
    url(r'^posts/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^posts/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.post_detail),
]

# Cách viết cho Django 2.0
from django.urls import path, re_path

urlpatterns = [
    path('posts/2003/', views.case_2003),
    path('posts/<int:year>/', views.year_archive),
    path('posts/<int:year>/<int:month>/', views.month_archive),
    path('posts/<int:year>/<int:month>/<slug:slug>/', views.post_detail),
]
  • Tham khảo tài liệu chính thức
  • Trong phiên bản 2.0, re_path và url trong phiên bản 1.11 có cách dùng giống nhau.
  • Chi tiết biểu thức chính quy
# Lưu ý quan trọng
1 Các phần tử trong urlpatterns được kiểm tra theo thứ tự từ trên xuống dưới, một khi khớp thành công sẽ không tiếp tục kiểm tra nữa.
2 Để lấy giá trị từ URL, chỉ cần đặt nó trong cặp dấu ngoặc đơn (khớp nhóm).
3 Không cần thêm dấu gạch chéo phía trước vì mỗi URL đều có sẵn. Ví dụ, nên dùng ^posts thay vì ^/posts.
4 Ký tự 'r' phía trước mỗi biểu thức chính quy là tùy chọn nhưng khuyến nghị thêm vào.
5 Mỗi biểu thức nên có ký hiệu bắt đầu và kết thúc để logic chặt chẽ hơn, ví dụ ^posts/$
  • Giải thích bổ sung

# Tham số cấu hình cho việc chuyển hướng URL không có dấu / ở cuối sang URL có dấu /
APPEND_SLASH=True
File cấu hình Django settings.py mặc định không có tham số APPEND_SLASH này, nhưng Django mặc định thiết lập 
APPEND_SLASH = True. Chức năng của nó là tự động thêm '/' vào cuối địa chỉ URL.

Hiệu quả đạt được là:

Chúng ta định nghĩa urls.py:

from django.conf.urls import url
from myapp import views

urlpatterns = [
    url(r'^blog/$', views.blog),
]
Khi truy cập http://www.example.com/blog, hệ thống sẽ tự động chuyển đổi địa chỉ thành http://www.example.com/blog/ .

Nếu trong settings.py thiết lập APPEND_SLASH=False, lúc này khi yêu cầu http://www.example.com/blog sẽ nhận được thông báo không tìm thấy trang.

Phân nhóm

url(r'^blog/([0-9]{4})/$', views.blogs),    ——> Phân nhóm  Truyền tham số đã bắt được theo cơ chế truyền tham số vị trí cho hàm view   #tham số là kiểu str

# Trong views.py, nhận tham số nhóm
def page(request, number):
    print(number)    # Nếu truyền tham số int thì kiểu dữ liệu của number là int, mỗi nhóm cần có một tham số tương ứng để nhận giá trị
    return HttpResponse('ok')

Phân nhóm có tên (khuyến nghị sử dụng phân nhóm có tên)

url(r'^blog/(?P<year>[0-9]{4})/$', views.blogs),   ——> Phân nhóm có tên  Truyền tham số đã bắt được theo cơ chế truyền tham số keyword cho hàm view 
 #kiểu dữ liệu tham số str, ở đây ?P<year> có year thì hàm view cũng phải dùng tên tương ứng để nhận year

# Trong views.py, nhận tham số nhóm
def page(request, year):
    print(year)        #Tên phải tương ứng chính xác với tên nhóm    
    return HttpResponse('ok')
  • Tổng kết nhỏ
Vị trí khớp trong URLconf
URLconf tìm kiếm trên URL yêu cầu, xử lý nó như một chuỗi Python thông thường. Không bao gồm tham số GET và POST cũng như tên miền.

Ví dụ, trong yêu cầu http://www.example.com/myapp/, URLconf sẽ tìm kiếm /myapp/ .

Trong yêu cầu http://www.example.com/myapp/?page=3, URLconf vẫn sẽ tìm kiếm /myapp/ .

URLconf không kiểm tra phương thức yêu cầu. Nói cách khác, tất cả các phương thức yêu cầu —— POST, GET, HEAD, v.v. cho cùng một URL —— đều sẽ được định tuyến đến cùng một hàm.

Các tham số bắt được luôn là chuỗi
Mỗi tham số bắt được trong URLconf đều được truyền cho view dưới dạng chuỗi Python thông thường, bất kể biểu thức chính quy sử dụng phương pháp khớp nào. Ví dụ, trong dòng URLconf sau:

url(r'^posts/(?P<year>[0-9]{4})/$', views.year_archive),
Tham số year được truyền cho hàm view views.year_archive() luôn là kiểu chuỗi.

Chỉ định giá trị mặc định

# Trong urls.py
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^blog/$', views.page),  # Không truyền tham số, sử dụng giá trị mặc định number = '1'
    url(r'^blog/page(?P<number>[0-9]+)/$', views.page),# Truyền tham số, và number = bất kỳ số nào từ '0-9', sẽ thay thế number = '1'
]

# Trong views.py, có thể chỉ định giá trị mặc định cho number
def page(request, number="1"):
    pass

Trong ví dụ trên, hai mẫu URL trỏ đến cùng một view - views.page - nhưng mẫu đầu tiên không bắt bất kỳ thứ gì từ URL.

Nếu mẫu đầu tiên khớp, hàm page() sẽ sử dụng tham số mặc định number="1", nếu mẫu thứ hai khớp, page() sẽ sử dụng giá trị number bắt được từ biểu thức chính quy.

Phân phối định tuyến bằng include


"""
Trong môi trường phát triển thực tế, chúng ta có thể cần phát triển nhiều chức năng, có nhiều app phân chia theo chức năng, cần sử dụng phân phối định tuyến, URL gốc chịu trách nhiệm phân phối các yêu cầu trang khác nhau đến các URL tương ứng trong từng app để thực hiện chương trình phản hồi.
"""

Cách viết URL trong file urls.py của thư mục dự án (định tuyến gốc):
    from django.conf.urls import url,include
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^$', views.base), # Định tuyến trang chủ
        url(r'^app01/', include('app01.urls')),# Phân phối đến app01
        url(r'^app02/', include('app02.urls')),# Phân phối đến app02
    ]
    
Cách viết nội dung trong urls.py của app01
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^$', views.app01base),# Định tuyến trang chủ app01
        url(r'^index/', views.index),
    ]
    
Cách viết nội dung trong urls.py của app02   
    from django.conf.urls import url
    from django.contrib import admin
    from app02 import views

    urlpatterns = [
        url(r'^$', views.app02base),# Định tuyến trang chủ app02
        url(r'^home/', views.home),
    ]

Truyền tham số bổ sung cho hàm view (kiến thức nâng cao)

URLconf có một cơ chế hook cho phép bạn truyền một từ điển Python làm tham số bổ sung cho hàm view.

django.conf.urls.url() có thể nhận tham số thứ ba tùy chọn, là một từ điển, biểu thị các tham số keyword bổ sung muốn truyền cho hàm view.

Ví dụ:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'extra': 'value'}),
]
Trong ví dụ này, cho yêu cầu /blog/2005/, Django sẽ gọi views.year_archive(request, year='2005', extra='value').
Khi tên tham số trong từ điển tham số bổ sung trùng với tên tham số keyword bắt được từ URL, hàm gọi sẽ sử dụng tham số từ từ điển,
chứ không phải tham số bắt được từ URL.

URL có tên và phân tích ngược URL

Tài liệu chính thức

Khi sử dụng dự án Django, nhu cầu phổ biến là lấy được dạng cuối cùng của URL, để nhúng vào nội dung tạo ra (URL trong view và hiển thị cho người dùng, v.v.) hoặc để xử lý điều hướng phía máy chủ (chuyển hướng, v.v.). Người dùng rất mong muốn không phải mã hóa cứng các URL này (tốn công, không mở rộng được và dễ gây lỗi) hoặc thiết kế cơ chế tạo URL chuyên biệt không liên quan gì đến URLconf, vì điều này dễ dẫn đến việc tạo ra URL lỗi thời ở một mức độ nào đó. Nói cách khác, cần một cơ chế DRY. Ngoài các lợi ích khác, nó còn cho phép URL được thiết kế tự động cập nhật mà không cần duyệt qua mã nguồn của dự án để tìm và thay thế các URL lỗi thời. Thông tin đầu tiên cần biết để lấy một URL là định danh của view xử lý nó (ví dụ như tên), các thông tin cần thiết khác để tìm URL đúng là loại tham số view (tham số vị trí, tham số keyword) và giá trị. Django cung cấp một cách để URL mapping là nơi duy nhất thiết kế URL. Bạn điền vào URLconf của mình, sau đó có thể sử dụng nó theo hai chiều: Theo yêu cầu URL từ người dùng/trình duyệt, nó gọi đúng view Django và trích xuất các giá trị tham số cần thiết từ URL. Theo định danh view Django và giá trị tham số sẽ truyền cho nó, lấy URL liên kết với nó. Cách thứ nhất là cách dùng chúng ta đã thảo luận trong các chương trước. Cách thứ hai gọi là phân tích ngược URL, khớp ngược URL, truy vấn ngược URL hoặc đơn giản là tra cứu URL ngược. Ở những nơi cần URL, cho các cấp độ khác nhau, Django cung cấp các công cụ khác nhau cho tra cứu URL ngược: Trong template: sử dụng tag template url. Trong mã Python: sử dụng hàm django.core.urlresolvers.reverse(). Trong mã cấp cao hơn liên quan đến xử lý instance model Django: sử dụng phương thức get_absolute_url(). Nói dài dòng như trên, bạn có thể chưa hiểu rõ. (Đó là bản dịch cứng từ tài liệu chính thức). Chúng ta nói đơn giản là có thể đặt tên cho quy tắc khớp URL của chúng ta, mỗi mẫu khớp URL đặt một tên. Như vậy sau này chúng ta không cần viết cứng mã URL nữa, chỉ cần gọi URL hiện tại thông qua tên.
  • Đặt tên cho mẫu khớp URL
# Định tuyến tĩnh
url(r'^home', views.home, name='home'),  # Đặt tên cho mẫu khớp URL là home   

# Định tuyến nhóm động
url(r'^index/(\d*)', views.index, name='index'),  # Đặt tên cho mẫu khớp URL là index

## Định tuyến nhóm có tên động
url(r'^index/(?P<number>[0-9]{4})/(?P<month>\d{2})', views.index, name='index'),  # Đặt tên cho mẫu khớp URL là index
  • Sử dụng phân tích ngược trong template
# Tĩnh
{% url 'home' %}  # Lấy đường dẫn đầy đủ của mẫu khớp URL có tên là home

# Nhóm động
{% url 'index' 2019 %}  # Thêm tham số sau khoảng trắng, nhiều tham số cách nhau bởi khoảng trắng, số lượng tham số phải khớp với số nhóm

# Nhóm có tên động
{% url 'index' 2019 12 %}  # Thứ tự không được sai  truyền tham số theo vị trí
# hoặc
{% url 'index' month=12 year=2019 %} # Thứ tự không yêu cầu
  • Sử dụng phân tích ngược trong hàm views
# Tĩnh
from django.urls import reverse

reverse('home') # Lấy đường dẫn đầy đủ của mẫu khớp URL có tên là home

# Nhóm động
reverse("index", args=('2018', )) # Với một nhóm, phải thêm dấu phẩy sau ('2018',), nhiều nhóm tương ứng nhiều tham số, viết sau 2018, là được ('2018','06')  truyền tham số theo vị trí

# Nhóm có tên động
reverse("index", args=('2018','12' )) # Thứ tự không được sai truyền tham số theo vị trí
# hoặc
reverse("index", kwargs={'year':'2018', 'month':'12'})
  • Tóm tắt: Phân tích ngược là theo biệt danh url lấy được đường dẫn URL đầy đủ, dù đường dẫn url thay đổi thế nào, vẫn có thể lấy được đường dẫn URL đầy đủ bình thường

Mô hình không gian tên

  • Ngay cả khi các APP khác nhau sử dụng tên URL giống nhau, mô hình không gian tên URL vẫn cho phép bạn đảo ngược duy nhất các URL có tên.
  • Ví dụ: urls.py trong project
from django.conf.urls import url, include # Nhập include
 
urlpatterns = [
    url(r'^app01/', include('app01.urls', namespace='app01')),# Thiết lập không gian tên
    url(r'^app02/', include('app02.urls', namespace='app02')),
]
  • urls.py trong app01
from django.conf.urls import url
from app01 import views
 
#app_name = 'app01'
urlpatterns = [
    url(r'^(?P<id>\d+)/$', views.detail, name='detail')
]
  • urls.py trong app02
from django.conf.urls import url
from app02 import views
 
#app_name = 'app02'
urlpatterns = [
    url(r'^(?P<id>\d+)/$', views.detail, name='detail')
]
  • Bây giờ, hai app của tôi có tên URL trùng nhau, tôi có thể đảo ngược URL thông qua tên không gian tên để lấy được URL hiện tại.
  • Cú pháp:
# Tên không gian tên:Tên URL
# Sử dụng trong template:
{% url 'app01:detail' id=12 param=99 %}

  • Sử dụng trong hàm trong views
v = reverse('app01:detail', kwargs={'id':11,'param':99})

  • Như vậy ngay cả khi tên URL trong app giống nhau, tôi cũng có thể đảo ngược để lấy được URL đúng.

Thẻ: Django Routing url-configuration web-framework python

Đăng vào ngày 21 tháng 5 lúc 11:30