1. 程式人生 > >Django 視圖與網址進階

Django 視圖與網址進階

ges ces 也會 視圖 ngx padding request hat 技術分享

一 、在網頁上做加減法

1. 采用 /add/?a=4&b=5 這樣GET方法進行

1 2 3 django-admin.py startproject zqxt_views cd zqxt_views python manage.py startapp calc

自動生成目錄大致如下(因不同的 Django 版本有一些差異,如果差異與這篇文章相關,我會主動提出來,沒有說的,暫時可以忽略他們之間的差異,後面的教程也是這樣做):

1 2 3 4 5 6 7 8 9 10 11 12 13 zqxt_views/ ├── calc │ ├── __init__.py
│ ├── admin.py │ ├── models.py │ ├── tests.py │ └── views.py ├── manage.py └── zqxt_views ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py

我們修改一下 calc/views.py文件

1 2 3 4 5 6 7 8 from django.shortcuts import render from django.http import HttpResponse def add(request):
a = request.GET[‘a‘] b = request.GET[‘b‘] c = int(a)+int(b) return HttpResponse(str(c))

註:request.GET 類似於一個字典,更好的辦法是用 request.GET.get(‘a‘, 0) 當沒有傳遞 a 的時候默認 a 為 0

接著修改 zqxt_views/urls.py 文件,添加一個網址來對應我們剛才新建的視圖函數。

Django 1.7.x 及以下的同學可能看到的是這樣的:

1 2 3 4 5 6 7 8 9 10 11 12 from django.conf.urls
import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns(‘‘, # Examples: url(r‘^add/$‘, ‘calc.views.add‘, name=‘add‘), # 註意修改了這一行 # url(r‘^blog/‘, include(‘blog.urls‘)), url(r‘^admin/‘, include(admin.site.urls)), )

Django 1.8.x及以上,Django 官方鼓勵(或說要求)先引入,再使用。

1 2 3 4 5 6 7 8 9 from django.conf.urls import url from django.contrib import admin from calc import views as calc_views urlpatterns = [ url(r‘^add/$‘, calc_views.add, name=‘add‘), # 註意修改了這一行 url(r‘^admin/‘, admin.site.urls), ]

註意:低版本的 Django 也可以先引入,再使用

Django 2.0 版本的同學看下面(上面 Django 1.8 的在 2.0 中也可以用,是兼容的)

1 2 3 4 5 6 7 8 9 from django.contrib import admin from django.urls import path from calc import views as calc_views urlpatterns = [ path(‘add/‘, calc_views.add, name=‘add‘), # new path(‘admin/‘, admin.site.urls), ]

我們打開開發服務器並訪問

1 2 3 python manage.py runserver 8002 默認端口是 8000,上面使用了自定義端口 8002 如果提示 Error: That port is already in use. 我們可以在後面加上端口號8001,8888等

打開網址:http://127.0.0.1:8002/add/ 就可以看到

MultiValueDictKeyError at /add/

技術分享圖片

這是因為我們並沒有傳值進去,我們在後面加上 ?a=4&b=5,即訪問 http://127.0.0.1:8002/add/?a=4&b=5

就可以看到網頁上顯示一個 9,試著改變一下a和b對應的值試試看?

技術分享圖片

技術分享圖片

2. 采用 /add/3/4/ 這樣的網址的方式

前面介紹的時候就說過 Django 支持優雅的網址

我們接著修改 calc/views.py文件,再新定義一個add2 函數,原有部分不再貼出

1 2 3 def add2(request, a, b): c = int(a) + int(b) return HttpResponse(str(c))

接著修改 zqxt_views/urls.py 文件,再添加一個新的 url

Django 1.7.x 及以下:

1 url(r‘^add/(\d+)/(\d+)/$‘, ‘calc.views.add2‘, name=‘add2‘),

Django 1.8.x - Django 1.11.x:

1 url(r‘^add/(\d+)/(\d+)/$‘, calc_views.add2, name=‘add2‘),

Django 2.0 及以上:

1 path(‘add/<int:a>/<int:b>/‘, calc_views.add2, name=‘add2‘),

我們可以看到網址中多了 (\d+), 正則表達式中 \d 代表一個數字,+ 代表一個或多個前面的字符,寫在一起 \d+ 就是一個或多個數字,用括號括起來的意思是保存為一個子組(更多知識請參見Python 正則表達式),每一個子組將作為一個參數,被 views.py 中的對應視圖函數接收。

我們再訪問 http://127.0.0.1:8002/add/4/5/ 就可以看到和剛才同樣的效果,但是這回網址更優雅了

技術分享圖片

二、URL name詳解

教程中所有的文件,沒有特別說明的,都是以 utf8 格式編碼的,請養成這個習慣。

1. 打開 zqxt_views/urls.py

1 2 3 4 5 6 7 8 9 10 from django.conf.urls import url from django.contrib import admin from calc import views as calc_views urlpatterns = [ url(r‘^add/$‘, calc_views.add, name=‘add‘), url(r‘^add/(\d+)/(\d+)/$‘, calc_views.add2, name=‘add2‘), url(r‘^admin/‘, admin.site.urls), ]

url(r‘^add/$‘, calc_views.add, name=‘add‘), 這裏的 name=‘add‘ 是用來幹什麽的呢?

簡單說,name 可以用於在 templates, models, views ……中得到對應的網址,相當於“給網址取了個名字”,只要這個名字不變,網址變了也能通過名字獲取到。

為了進一步弄清這個問題,我們先建一個首頁的視圖和url

2. 修改 calc/views.py

1 2 3 4 5 6 7 8 9 from django.http import HttpResponse from django.shortcuts import render def index(request): return render(request, ‘home.html‘) ...此處省去一些代碼

render 是渲染模板,不懂先照著打就好。

3. 將 ‘calc‘ 這個 app 加入到 zqxt_views/settings.py 中

1 2 3 4 5 6 7 8 9 10 INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ‘calc‘, ]

這樣,使用render的時候,Django 會自動找到 INSTALLED_APPS 中列出的各個 app 下的 templates 中的文件。

小提示,DEBUG=True 的時候,Django 還可以自動找到 各 app 下 static 文件夾中的靜態文件(js,css,圖片等資源),方便開發,後面有專門的章節會講這些。

4. 我們在 calc 這個 app 中新建一個 templates 文件夾,在templates中新建一個 home.html (關於模板更詳細的可以稍後看下一節)

文件 calc/templates/home.html 中寫入以下內容(保存時用 utf8 編碼

1 2 3 4 5 6 7 8 9 10 11 <!DOCTYPE html> <html> <head> <title>自強學堂</title> </head> <body> <a href="/add/4/5/">計算 4+5</a> </body> </html>

修改 zqxt_views/urls.py

1 2 3 4 5 6 7 8 ...此處省去一些代碼 urlpatterns = [ url(r‘^$‘, calc_views.index, name=‘home‘), url(r‘^add/$‘, calc_views.add, name=‘add‘), url(r‘^add/(\d+)/(\d+)/$‘, calc_views.add2, name=‘add2‘), url(r‘^admin/‘, admin.site.urls), ]

運行開發服務器,我們訪問 http://127.0.0.1:8000/ 可以看到

技術分享圖片

我們計算加法的時候用的是 /add/4/5/ ,後來需求發生變化,比如改成 /4_add_5/,但在網頁中,代碼中很多地方都寫死的 /add/4/5/,比如模板中可能是這麽寫的

1 <a href="/add/4/5/">計算 4+5</a>

如果這樣寫“死網址”,會使得在改了網址(正則)後,模板(template),視圖(views.py,比如用於URL跳轉),模型(models.py,獲取記錄訪問地址等)用了此網址的,都必須進行相應的更改,修改的代價很大,一不小心,有的地方沒改過來,就不能用了

那麽有沒有更優雅的方式來解決這個問題呢?當然答案是肯定的。

我們先說一下如何用 Python 代碼獲取對應的網址(可以用在 views.py,models.py等各種需要轉換得到網址的地方):

我們在終端上輸入(推薦安裝 bpython, 這樣Django會用 bpython的 shell)

1 python manage.py shell

1 2 3 4 5 6 7 8 >>> from django.core.urlresolvers import reverse # django 1.4.x - django 1.10.x 或者 >>> from django.urls import reverse # Django 1.10.x - Django 2.x 新的,更加規範了 >>> reverse(‘add2‘, args=(4,5)) u‘/add/4/5/‘ >>> reverse(‘add2‘, args=(444,555)) u‘/add/444/555/‘

reverse 接收 url 中的 name 作為第一個參數,我們在代碼中就可以通過 reverse() 來獲取對應的網址(這個網址可以用來跳轉,也可以用來計算相關頁面的地址),只要對應的 url 的name不改,就不用改代碼中的網址。

在網頁模板中也是一樣,可以很方便的使用。

1 2 3 4 5 6 7 不帶參數的: {% url ‘name‘ %} 帶參數的:參數可以是變量名 {% url ‘name‘ 參數 %} 例如: <a href="{% url ‘add2‘ 4 5 %}">link</a>

上面的代碼渲染成最終的頁面是

1 <a href="/add/4/5/">link</a>

這樣就可以通過 {% url ‘add2‘ 4 5 %} 獲取到對應的網址 /add/4/5/

當 urls.py 進行更改,前提是不改 name(這個參數設定好後不要輕易改),獲取的網址也會動態地跟著變,比如改成:

1 url(r‘^new_add/(\d+)/(\d+)/$‘, calc_views.add2, name=‘add2‘),

註意看重點 add 變成了 new_add,但是後面的 name=‘add2‘ 沒改,這時 {% url ‘add2‘ 4 5 %} 就會渲染對應的網址成 /new_add/4/5/

用在 views.py 或 models.py 等地方的 reverse函數,同樣會根據 name 對應的url獲取到新的網址。

想要改網址的時候,修改 urls.py 中的正則表達式部分(url 參數第一部分),name 不變的前提下,其它地方都不需要修改。

另外,比如用戶收藏夾中收藏的URL是舊的,如何讓以前的 /add/3/4/自動跳轉到現在新的網址呢?

要知道Django不會幫你做這個,這個需要自己來寫一個跳轉方法

具體思路是,在 views.py 寫一個跳轉的函數:

1 2 3 4 5 6 7 8 9 from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse # Django 1.4.x - Django 1.10.x # from django.urls import reverse # Django 1.10.x - Django 2.x def old_add2_redirect(request, a, b): return HttpResponseRedirect( reverse(‘add2‘, args=(a, b)) )

urls.py中:

1 2 url(r‘^add/(\d+)/(\d+)/$‘, calc_views.old_add2_redirect), url(r‘^new_add/(\d+)/(\d+)/$‘, calc_views.add2, name=‘add2‘),

這樣,假如用戶收藏夾中有 /add/4/5/ ,訪問時就會自動跳轉到新的 /new_add/4/5/ 了

Django 視圖與網址進階