url路由層

urls.py 路由層

路由與視圖函數對應關係 >>> 路由層前端

URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表。python

你就是以這種方式告訴Django,對於這個URL調用這段代碼,對於那個URL調用那段代碼。nginx

URLconf配置

基本格式:git

from django.conf.urls import url

urlpatterns = [
     url(正則表達式, views視圖函數,參數,別名),
]

注意:正則表達式

Django 2.0版本中的路由系統已經替換成下面的寫法(官方文檔):django

from django.urls import path

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

舉例:後端

from django.conf.urls import url
from django.contrib import admin
from app02 import views
urlpatterns = [
    url(r'^book_list/', views.book_list),
    url(r'test', views.test),
    
    url(r'test_add', views.test_add),
]

url內部的規則

參數說明瀏覽器

  1. url第一個參數是一個正則表達式
  2. 一旦匹配上了 會馬上執行對應的視圖函數 再也不往下匹配了
  3. 正則表達式:一個正則表達式字符串
  4. views視圖函數:一個可調用對象,一般爲一個視圖函數或一個指定視圖函數路徑的字符串
  5. 參數:可選的要傳遞給視圖函數的默認參數(字典形式)
  6. 別名:一個可選的name參數

注意服務器

  • 若要從URL 中捕獲一個值,只須要在它周圍放置一對圓括號。
  • 不須要添加一個前導的反斜槓,由於每一個URL 都有。例如,應該是^articles 而不是 ^/articles
  • 每一個正則表達式前面的'r' 是可選的可是建議加上。它告訴Python 這個字符串是「原始的」 —— 字符串中任何字符都不該該轉義
  • urlpatterns中的元素按照書寫順序從上往下逐一匹配正則表達式,一旦匹配成功則再也不繼續

示例:

'''
 一些請求的例子:

/articles/2005/03/ 請求將匹配列表中的第三個模式。Django 將調用函數views.month_archive(request, '2005', '03')。
/articles/2005/3/ 不匹配任何URL 模式,由於列表中的第三個模式要求月份應該是兩個數字。
/articles/2003/ 將匹配列表中的第一個模式不是第二個,由於模式按順序匹配,第一個會首先測試是否匹配。請像這樣自由插入一些特殊的狀況來探測匹配的次序。
/articles/2003 不匹配任何一個模式,由於每一個模式要求URL 以一個反斜線結尾。
/articles/2003/03/03/ 將匹配最後一個模式。Django 將調用函數views.article_detail(request, '2003', '03', '03')。
   
    '''

APPEND_SLASH

APPEND_SLASH:是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑的配置項

# 是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑的配置項
APPEND_SLASH=True

Django settings.py配置文件中默認沒有 APPEND_SLASH 這個參數,但 Django 默認這個參數爲 APPEND_SLASH = True。 其做用就是自動在網址結尾加'/'。

其效果就是:

咱們定義了urls.py:

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

urlpatterns = [
        url(r'^blog/$', views.blog),
]

訪問 http://www.example.com/blog 時,默認將網址自動轉換爲 http://www.example/com/blog/

若是在settings.py中設置了 APPEND_SLASH=False,此時咱們再請求 http://www.example.com/blog 時就會提示找不到頁面。

無名分組與有名分組

分組:給某一段正則表達式加括號

在使用Django 項目時,一個常見的需求是得到URL的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。
人們強烈但願不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 絕不相關的專門的URL 生成機制,由於這樣容易致使必定程度上產生過時的URL。
換句話講,須要的是一個DRY 機制。除了其它有點,它還容許設計的URL 能夠自動更新而不用遍歷項目的源代碼來搜索並替換過時的URL。
獲取一個URL 最開始想到的信息是處理它視圖的標識(例如名字),查找正確的URL 的其它必要的信息有視圖參數的類型(位置參數、關鍵字參數)和值。
Django 提供一個辦法是讓URL 映射是URL 設計惟一的地方。你填充你的URLconf,而後能夠雙向使用它:

  • 根據用戶/瀏覽器發起的URL 請求,它調用正確的Django 視圖,並從URL 中提取它的參數須要的值。
  • 根據Django 視圖的標識和將要傳遞給它的參數的值,獲取與之關聯的URL。

第一種方式是咱們在前面的章節中一直討論的用法。第二種方式叫作反向解析URL、反向URL 匹配、反向URL 查詢或者簡單的URL 反查。
在須要URL 的地方,對於不一樣層級,Django 提供不一樣的工具用於URL 反查:

  • 在模板中:使用url模板標籤。
  • 在Python 代碼中:使用django.core.urlresolvers.reverse() 函數。
  • 在更高層的與處理Django 模型實例相關的代碼中:使用get_absolute_url() 方法。

上面說了一大堆,你可能並無看懂。(那是官方文檔的生硬翻譯)。

我們簡單來講就是能夠給咱們的URL匹配規則起個名字,一個URL匹配模式起一個名字。

這樣咱們之後就不須要寫死URL代碼了,只須要經過名字來調用當前的URL。

舉個簡單的例子:

url(r'^home', views.home, name='home'),  # 給個人url匹配模式起名爲 home
url(r'^index/(\d*)', views.index, name='index'),  # 給個人url匹配模式起名爲index

這樣:

在模板裏面能夠這樣引用:

{% url 'home' %}

在views函數中能夠這樣引用:

from django.urls import reverse

reverse("index", args=("2018", ))

例子:
考慮下面的URLconf:

from django.conf.urls import url

from . import views

urlpatterns = [
    # ...
    url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    # ...
]

根據這裏的設計,某一年nnnn對應的歸檔的URL是/articles/nnnn/

你能夠在模板的代碼中使用下面的方法得到它們:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

在Python 代碼中,這樣使用:

from django.urls import reverse
from django.shortcuts import redirect

def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return redirect(reverse('news-year-archive', args=(year,)))

若是出於某種緣由決定按年歸檔文章發佈的URL應該調整一下,那麼你將只須要修改URLconf 中的內容。

在某些場景中,一個視圖是通用的,因此在URL 和視圖之間存在多對一的關係。對於這些狀況,當反查URL 時,只有視圖的名字還不夠。

注意:

爲了完成上面例子中的URL 反查,你將須要使用命名的URL 模式。URL 的名稱使用的字符串能夠包含任何你喜歡的字符。不僅限制在合法的Python 名稱。

當命名你的URL 模式時,請確保使用的名稱不會與其它應用中名稱衝突。若是你的URL 模式叫作comment,而另一個應用中也有一個一樣的名稱,當你在模板中使用這個名稱的時候不能保證將插入哪一個URL。

在URL 名稱中加上一個前綴,好比應用的名稱,將減小衝突的可能。咱們建議使用myapp-comment 而不是comment

無名分組

urlpatterns = [
    url(r'^test/(\d+)', views.test),
]

會將括號內匹配到的內容當作 位置參數 傳遞給後面的視圖函數

def test(request,args):
    print(args)
    return HttpResponse('test')

有名分組:給正則表達式起別名

urlpatterns = [
    url(r'^test/(?P<year>\d+)', views.test),
]

會將括號內匹配到的內容當作 關鍵字參數 傳遞給後面的視圖函數

方式1
# def test(request,**kwargs):
#     print(kwargs)
#     return HttpResponse('test')
方式2
def test(request,year):
    print(year,1)
    return HttpResponse('test')
  1. 無名和有名可否結合使用
    不能結合使用,可是無名和有名 可使用屢次
  2. 有名無名單獨使用的狀況下 能夠用多個
url(r'^test/(\d+)/(\d+)/', views.test),
   url(r'^test/(?P<xxx>\d+)/(?P<month>\d+)/', views.test),

反向解析

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

在須要URL 的地方,對於不一樣層級,Django 提供不一樣的工具用於URL 反查:

  • 在模板中:使用url 模板標籤。
  • 在Python 代碼中:使用from django.urls import reverse()函數

​ 根據某一個東西 動態解析出一個結果 該結果能夠直接訪問對應的url

url(r'^test_add/', views.testadd,name='xxx')

前端解析
    {% url 'xxx' %}

後端解析
    from django.shortcuts import render,HttpResponse,redirect,reverse
    url = reverse('xxx')

無名分組反向解析

url(r'^test_addsajdsjkahdkjasjkdh/(\d+)/', views.testadd,name='xxx'),
前端解析
        <a href="{% url 'xxx' 1 %}">222</a>
    
    後端解析
        url = reverse('xxx',args=(1,))

有名分組反向解析

url(r'^test_addsajdsjkahdkjasjkdh/(?P<year>\d+)/', views.testadd,name='xxx')
前端解析
        <a href="{% url 'xxx' 1 %}">222</a>
        
        <a href="{% url 'xxx' year=1 %}">222</a>
    
    後端解析
        url = reverse('xxx',args=(1,))
        url = reverse('xxx',kwargs={'year':123})

注意 反向解析的別名 必定不要重複

路由分發(******)

django裏面的app能夠有本身的static文件,templates文件夾,urls.py(******)   

項目名下面的urls.py再也不作路由與視圖函數對應關係
而是作一箇中轉站  只負責將請求分發到不一樣的app中 
而後在app的urls.py完成路由與視圖函數的對應關係
from django.conf.urls import url,include

url(r'^app01/',include(app01_urls)),
url(r'^app02/',include(app02_urls))

名稱空間

命名空間(英語:Namespace)是表示標識符的可見範圍。一個標識符可在多個命名空間中定義,它在不一樣命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何標識符,它們不會與任何已有的標識符發生衝突,由於已有的定義都處於其它命名空間中。

因爲name沒有做用域,Django在反解URL時,會在項目全局順序搜索,當查找到第一個name指定URL時,當即返回

咱們在開發項目時,會常用name屬性反解出URL,當不當心在不一樣的app的urls中定義相同的name時,可能會致使URL反解錯誤,爲了不這種事情發生,引入了命名空間。

解決各個app之間命名的重複 ,django是分不清楚。

​ 總路由
​ url(r'^app01/',include('app01.urls',namespace='app01'))
​ url(r'^app02/',include('app02.urls',namespace='app02'))

print(reverse('app01:index'))
    print(reverse('app02:index'))

一般狀況下 起別名的時候 前面能夠加上你的應用名

建立一個app02:python manage.py startapp app02

urls.py

from django.urls import path,re_path,include
urlpatterns = [
    path('app01/', include('app01.urls')),
    path('app02/', include('app02.urls'))
]

app01 的urls.py

from django.urls import path,re_path
from app01 import views
urlpatterns = [
    re_path(r'index/',views.index,name='index'),
]

app02 的urls.py

from django.urls import path, re_path, include
from app02 import views

urlpatterns = [
    re_path(r'index/', views.index,name='index'),

]

app01的視圖函數

def index(request):
    url=reverse('index')
    print(url)
    return HttpResponse('index app01')

app02的視圖函數

def index(request):
    url=reverse('index')
    print(url)
    return HttpResponse('index app02')

這樣都找index,app01和app02找到的都是app02的index

如何處理?在路由分發的時候指定名稱空間

總urls.py在路由分發時,指定名稱空間

path('app01/', include(('app01.urls','app01'))),
 path('app02/', include(('app02.urls','app02')))
 url(r'app01/',include('app01.urls',namespace='app01')),
 url(r'app02/',include('app02.urls',namespace='app02'))
 url(r'app01/',include(('app01.urls','app01'))),
 url(r'app02/',include(('app02.urls','app02')))

在視圖函數反向解析的時候,指定是那個名稱空間下的

url=reverse('app02:index')
 print(url)
 url2=reverse('app01:index')
 print(url2)

在模版裏:

<a href="{% url 'app02:index'%}">哈哈</a>

僞靜態

  1. 將動態網頁僞裝成是靜態的(看起來是html頁面)
  2. 這樣作的目的是爲了提升搜索引擎的SEO查詢優先級
  3. 搜索在收錄網站的時候 會優先收錄看上去像是靜態文件的資源
  4. 可是不管你怎麼使用僞靜態進行優化 你也幹不過RMB玩家

虛擬環境

​ 一般針對不一樣的項目 只會安裝該項目所用的模塊 用不到的一律不裝

虛擬環境

  1. 不一樣的項目應該有各自獨立的解釋器環境 最大化節省資源

  2. 實際功能中針對不一樣的項目 會有一個叫requestsments.txt文件

  3. 該文件中列出來是一個個該項目須要用的到模塊名和版本號
    eg:
    django = 1.11.11
    nginx = 1.21

  4. 後期經過命令直接會去下載該文件內全部的模塊及對應版本

    不一樣的項目有專門的解釋器環境與之對應

    每建立一個虛擬環境 就相似於從新下載了一個純淨的python解釋器

    虛擬環境不要建立太多個
    建議 你的機器上不要有態多的虛擬環境
    當前咱們這個階段 建議你全部的模塊所有都安裝在本機環境中

虛擬環境的後期用法(瞭解)

python中經過requirements.txt來記錄項目全部的依賴包及其版本號,以便在其餘的環境中部署

(venv) $ pip freeze >requirements.txt

若是在開發的時候升級了依賴包,記得更新此文件!

在其餘環境部署項目以前先經過以下命令安裝依賴包,也就是當須要建立這個虛擬環境的徹底副本,能夠建立一個新的虛擬環境,並在其上運行如下命令:

(venv) $ pip install -r requirements.txt

pip的freeze命令保存了保存當前Python環境下全部類庫包,其它包括那些你沒有在當前項目中使用的類庫。 (若是你沒有的virtualenv)。

pip的freeze命令只保存與安裝在您的環境python全部軟件包。

但有時你只想將當前項目使用的類庫導出生成爲 requirements.txt;

使用方法:

$ pip install pipreqs $ pipreqs /path/to/project

django版本區別

​ django1.x
​ django2.x

區別1:
    urls.py中1.x用的是url,而2.x用的是path
    而且2.x中的path第一個不支持正則表達式,寫什麼就匹配什麼
    若是你以爲很差用,2.x裏面還有re_path 這個re_path就是你1.x裏面的url

django2.0的re_path和1.0的url同樣

思考狀況以下:

urlpatterns = [  
    re_path('articles/(?P<year>[0-9]{4})/', year_archive),  
    re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),  
]

考慮下這樣的兩個問題:

第一個問題,函數 year_archive 中year參數是字符串類型的,所以須要先轉化爲整數類型的變量值,固然year=int(year) 不會有諸如如TypeError或者ValueError的異常。那麼有沒有一種方法,在url中,使得這一轉化步驟能夠由Django自動完成?

第二個問題,三個路由中article_id都是一樣的正則表達式,可是你須要寫三遍,當以後article_id規則改變後,須要同時修改三處代碼,那麼有沒有一種方法,只需修改一處便可?

在Django2.0中,可使用 path 解決以上的兩個問題。

基本示例

這是一個簡單的例子:

from django.urls import path  
from . import views  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<int:year>/', views.year_archive),  
    path('articles/<int:year>/<int:month>/', views.month_archive),  
    path('articles/<int:year>/<int:month>/<slug>/', views.article_detail),  
  # path才支持,re_path不支持  path('order/<int:year>',views.order),
]

基本規則:

  • 使用尖括號(<>)從url中捕獲值。
  • 捕獲值中能夠包含一個轉化器類型(converter type),好比使用 <int:name> 捕獲一個整數變量。若果沒有轉化器,將匹配任何字符串,固然也包括了 / 字符。
  • 無需添加前導斜槓。

如下是根據 2.0官方文檔 而整理的示例分析表:(跟上面url的匹配關係)

path轉化器

文檔原文是Path converters,暫且翻譯爲轉化器。

Django默認支持如下5個轉化器:

  • str,匹配除了路徑分隔符(/)以外的非空字符串,這是默認的形式
  • int,匹配正整數,包含0。
  • slug,匹配字母、數字以及橫槓、下劃線組成的字符串。
  • uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
  • path,匹配任何非空字符串,包含了路徑分隔符(/)(不能用?)

註冊自定義轉化器

對於一些複雜或者複用的須要,能夠定義本身的轉化器。轉化器是一個類或接口,它的要求有三點:

  • regex 類屬性,字符串類型
  • to_python(self, value) 方法,value是由類屬性 regex 所匹配到的字符串,返回具體的Python變量值,以供Django傳遞到對應的視圖函數中。
  • to_url(self, value) 方法,和 to_python 相反,value是一個具體的Python變量值,返回其字符串,一般用於url反向引用。

例子:

class FourDigitYearConverter:  
    regex = '[0-9]{4}'  
    def to_python(self, value):  
        return int(value)  
    def to_url(self, value):  
        return '%04d' % value

使用register_converter 將其註冊到URL配置中:

from django.urls import register_converter, path  
from . import converters, views  
register_converter(converters.FourDigitYearConverter, 'yyyy')  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<yyyy:year>/', views.year_archive),  
    ...  
]
相關文章
相關標籤/搜索