Django-url反向解析和命名空間


一、urls硬編碼

在反向解析和命名空間之前我們先來說說URLS硬編碼,用django 開發應用的時候,可以完全是在urls.py 中硬編碼配置地址,在views.py中HttpResponseRedirect()也是硬編碼轉向地址,當然在template 中也是一樣了,這樣帶來一個問題,如果在urls.py 中修改了某個頁面的地址(也就是說更改路由系統中對應的路由分發),那么所有的地方(views.py和template中)都要修改。問題出在硬編碼,緊耦合使得在大量的模板中修改 URLs 成為富有挑戰性的項目。來看下面的模板文件index.html中,我們到的鏈接硬編碼成這樣子:

<li><a href="/goods/index/">url硬編碼</a></li>

如果使用軟編碼之后,無論怎么更改路由系統中的路由分發,只有對應的namespace與name屬性值不變,就不必修改在views.py和template中的url,也就是說

<li><a href="{% url "good:index" %}">url軟編碼</a></li>

在templates中更改為軟編碼之后,其實在templates,index.html文件生成的時候,仍然是

<li><a href="/goods/index/">url軟編碼</a></li>

 

二、URL的反向解析

在使用Django 項目時,一個常見的需求是獲得URL 的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。
人們強烈希望不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 毫不相關的專門的URL 生成機制,因為這樣容易導致一定程度上產生過期的URL。 

獲取一個URL 最開始想到的信息是處理它視圖的標識(例如名字),查找正確的URL 的其它必要的信息有視圖參數的類型(位置參數、關鍵字參數)和值。
Django 提供一個辦法是讓URL 映射是URL 設計唯一的地方。你填充你的URLconf,然后可以雙向使用它:
1、根據用戶/瀏覽器發起的URL 請求,它調用正確的Django 視圖,並從URL 中提取它的參數需要的值。
2、根據Django 視圖的標識和將要傳遞給它的參數的值,獲取與之關聯的URL。

第一種方式是我們常說的根據地址定位URL。

第二種方式叫做反向解析URL、反向URL 匹配、反向URL 查詢或者簡單的URL 反查

在需要URL 的地方,對於不同層級,Django 提供不同的工具用於URL 反查:
1、在模板中:使用url 模板標簽。
2、在Python 代碼中:使用 django.core.urlresolvers.reverse() 函數。
3、在更高層的與處理Django 模型實例相關的代碼中:使用 get_absolute_url() 方法。

1、命名空間:

URL 命名空間允許你反查到唯一的命名URL 模式,即使不同的應用使用相同的URL 名稱。第三方應用始終使用帶命名空間的URL 是一個很好的實踐。類似地,它還允許你在一個應用有多個實例部署的情況下反查URL。換句話講,因為一個應用的多個實例共享相同的命名URL,命名空間將提供一種區分這些命名URL 的方法。

一個URL 命名空間有兩個部分,它們都是字符串:

<1>、應用命名空間:

它表示正在部署的應用的名稱。一個應用的每個實例具有相同的應用命名空間。例如,可以預見Django 的管理站點的應用命名空間是' admin '。

<2>、實例命名空間:

它表示應用的一個特定的實例。實例的命名空間在你的全部項目中應該是唯一的。但是,一個實例的命名空間可以和應用的命名空間相同。它用於表示一個應用的默認實例。例如,Django 管理站點實例具有一個默認的實例命名空間'admin'。 URL的命名空間使用':' 操作符指定。例如,管理站點應用的主頁使用' admin:index '。它表示' admin ' 的一個命名空間和' index ' 的一個命名URL.

# include函數的API
include(arg, namespace=None, app_name=None)
# namespace設置實例命名空間,app_name設置應用命名空間
# 不能只設置app_name,否則會報錯,以下是報錯的源碼
if app_name and not namespace:
    raise ValueError('Must specify a namespace if specifying app_name.')

一般來說,同一應用下的不同實例應該具有相同的應用命名空間,但是,這並不意味着不同應用可以使用相同的實例命名空間,因為實例命名空間在你所有項目中都是唯一的。

問題: 另外在添加命名空間 namespace時可能會出現以下這個問題:

    'Specifying a namespace in include() without providing an app_name '
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.

解決方案為:

在對應的app應用的urls.py中添加app_name = '[應用名稱]'如下

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

app_name = 'users'
# users為當前應用的名稱

urlpatterns = [
    url('^$', views.index),
    url('^(\d+)/$', views.detail),
]

三、url反向解析實例

在我們的django項目中通常App,目錄結構就可以如下daily_fresh_demo

daily_fresh_demo 
 |----daily_fresh_demo     |----__init__.py     |----settings.py     |----urls.py     |----wsgi.py   |----df_cart #對商品購物車管理 |---- migrations # 遷移文件目錄 |---- admin.py |---- apps.py |---- models.py |---- test.py |---- urls.py |---- views.py |---- __init__.py   |----df_goods  #商品以及后台管理 ...   |----df_user #用戶管理 ...   |----df_order #訂單管理 ...
  |----templates
     |index.html

 

1、路由分發:

 
         
daily_fresh_demo/daily_fresh_demo/urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include


urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^goods/', include('df_goods.urls', namespace='df_goods')),  # 添加實例命名空間
    url(r'^user/', include('df_user.urls', namespace='df_user')),
    url(r'^cart/', include('df_cart.urls', namespace='df_cart')),
    url(r'^order/', include('df_order.urls', namespace='df_order')),
]

根據路由分發到各個相應的app中。並添加實例命名空間

 

2、子路由

 
         
daily_fresh_demo/df_goods/urls.py

from
django.conf.urls import url from . import views app_name = 'df_goods' # 應用命名空間 urlpatterns = [ url('^index/$', views.index, name="index"), ]

df_goods中的路由,添加應用命名空間。並在url函數中添加name屬性。

3、視圖函數

daily_fresh_demo/df_goods/views.py

from django.shortcuts import render, reverse


def index(request):
    print(reverse("df_goods:index"))  # 利用reverse函數反向解析url
  # 打印結果為/goods/index/
return render(request, 'index.html')

4、靜態文件 index.html

daily_fresh_demo/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<a href="/goods/index">硬鏈接</a>
<a href="{% url "df_goods:index" %}">軟鏈接</a>
</body>
</html>

5、結果

靜態文件中index.html的url解析結果如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<a href="/goods/index">硬鏈接</a>
<a href="/goods/index/">軟鏈接</a>  # 軟編碼通過解析后得到的結果與硬編碼一致
</body>
</html>

 

總結:這樣一來通過命名空間,無論在templates文件中有多龐大的url地址映射,只要使用url軟編碼,在更改路由系統的時候,都能自動生成。而如果使用硬鏈接硬編碼 ,就只能在views.py和靜態文件中逐個修改url地址,不僅耗費時間,更容易產生錯誤。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM