第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

Django 入門教程

課程導(dǎo)學(xué)
Django 慕課教程使用指南
Django開發(fā)實(shí)戰(zhàn)
35 開發(fā)實(shí)戰(zhàn)
首頁 慕課教程 Django 入門教程 Django 入門教程 10 Django 中傳遞參數(shù)給視圖函數(shù)

Django 中傳遞參數(shù)給視圖函數(shù)

Django 框架中推薦使用一個單獨(dú)的 python 模塊配置 URL 和視圖函數(shù)或者視圖類的映射關(guān)系,通常稱這個配置模塊為 URLconf,該 Python 模塊通常命名為 urls.py。一般而言,每個應(yīng)用目錄下都會有一個 urls.py 文件,總的映射關(guān)系入口在項(xiàng)目目錄下的 urls.py 中,而這個位置又是在 settings.py 文件中指定的。

本小節(jié)中將會學(xué)習(xí) Django 中的路由系統(tǒng)、URLconf 的配置,以及如何將請求參數(shù),如表單數(shù)據(jù)、文件等傳遞給視圖函數(shù)。

1. 測試環(huán)境準(zhǔn)備

這里的實(shí)驗(yàn)環(huán)境會采用前面創(chuàng)建的第一個 Django 工程(first_django_app) 來進(jìn)行測試。在 first_django_app 中,我們創(chuàng)建了第一個 django app 應(yīng)用:hello_app?,F(xiàn)在按照如下步驟準(zhǔn)備實(shí)驗(yàn)環(huán)境:

在 hello_app 應(yīng)用目錄下的 views.py 中添加一個視圖函數(shù):

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.

def hello_view(request, *args, **kwargs):
    return HttpResponse('hello, world!')

在 hello_app 應(yīng)用目錄下新建 urls.py 文件,里面內(nèi)容如下:

from django.urls import path

from . import views

urlpatterns = [
    # 資產(chǎn)查詢接口,根據(jù)我們自己的機(jī)器命名
    path('world/', views.hello_view, name='hello_view'),
]

settings.py 文件中注冊應(yīng)用:

# first_django_app/settings.py
...

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 注冊應(yīng)用
    'hello_app'
]

...

在 URLconf 的總?cè)肟谖恢檬褂?django 提供的 include 方法將應(yīng)用中的 urls.py 中的 urlpatterns 添加進(jìn)來:

from django.contrib import admin
from django.conf.urls import include, url

# 所有url入口
urlpatterns = [
    url('admin/', admin.site.urls),
    url('hello/', include('hello_app.urls')),
]

這樣之后,我們請求地址 /hello/world/ 時,就能看到頁面顯示 “hello, world!” 字符了。后面的測試將在應(yīng)用的 urls.pyviews.py 中進(jìn)行。

2. Django 中的傳參方式

Django 中傳遞參數(shù)給視圖函數(shù)的方式主要可分為以下兩種形式:URL 傳參和非 URL 傳參兩種。第一種基于 Django 中的 URLconf 配置,可以通過 URL 路徑將對應(yīng)匹配的參數(shù)傳到視圖函數(shù)中;而另外一種就是屬于HTTP 請求攜帶的參數(shù)了,請求參數(shù)可以放到 URL 中以 ? 格式加到 URL 的最后面,也可以將參數(shù)放到請求 body 中,最后統(tǒng)一由視圖函數(shù)中的 request 參數(shù)保存并傳到視圖函數(shù)中。

2.1 動態(tài) URL 傳參

在 url 的路徑 (path)部分可以作為動態(tài)參數(shù),傳遞給視圖函數(shù),如下面幾種寫法:

# hello_app/urls.py
from django.urls import path

from . import views

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

注意上面的定義了匹配三個動態(tài) URL 的映射,每個動態(tài) URL 會匹配一個至多個參數(shù),每個動態(tài)值使用 <> 符號匹配,采用 <type:name> 這樣的形式。我們對應(yīng)的視圖函數(shù)如下:

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.

def year_archive(request, year, *args, **kwargs):
    return HttpResponse('hello, {} archive\n'.format(year))
    
def month_archive(request, year, month, *args, **kwargs):
    return HttpResponse('hello, month archive, year={}, moth={}!\n'.format(year, month))

def article_title(request, year, month, title, *args, **kwargs):
    return HttpResponse('hello, title archive, year={}, month={}, title={}!\n'.format(year, month, title))

對于動態(tài)的 URL 表達(dá)式中,匹配到的值,比如上面的 year,month 和 title 可以作為函數(shù)的參數(shù)放到對應(yīng)的視圖函數(shù)中,Django 會幫我們把匹配到的參數(shù)對應(yīng)的放到函數(shù)的參數(shù)上。這里參數(shù)的位置可以任意寫,但是名字必須和 URL 表達(dá)式中的對應(yīng)。

[root@server first_django_app]# curl http://127.0.0.1:8881/hello/articles/1998/
hello, 1998 archive
[root@server first_django_app]# curl http://127.0.0.1:8881/hello/articles/1998/12/
hello, month archive, year=1998, moth=12!
[root@server first_django_app]# curl http://127.0.0.1:8881/hello/articles/1998/12/test/
hello, title archive, year=1998, month=12, title=test

比如 URL 中有 3 個動態(tài)參數(shù),在視圖函數(shù)中只寫上兩個參數(shù)接收也是沒問題的,因?yàn)槭O碌膮?shù)會被傳到 kwargs 中以 key-value 的形式保存:

(django-manual) [root@server first_django_app]# cat hello_app/views.py
...

def article_title(request, year, month, *args, **kwargs):
    return HttpResponse('hello, title archive, year={}, month={}, kwargs={}\n'.format(year, month, kwargs))

# 啟動服務(wù),再次請求后
[root@server first_django_app]# curl http://127.0.0.1:8881/hello/articles/1998/12/test/
hello, title archive, year=1998, month=12, kwargs={'title': 'test'}

上述介紹的動態(tài) URL 匹配格式 <type:name> 中,Django 會對捕捉到的 URL 參數(shù)進(jìn)行強(qiáng)制類型裝換,然后賦給 name 變量,再傳到視圖函數(shù)中。其中 Django 框架中支持的轉(zhuǎn)換類型有:

  • str:匹配任意非空字符,不能匹配分隔符 “/”;

  • int:匹配任意大于0的整數(shù);

  • slug:匹配任意 slug 字符串, slug 字符串可以包含任意的 ASCII 字符、數(shù)字、連字符和下劃線等;

  • uuid:匹配 UUID 字符串;

  • path:匹配任意非空字符串,包括 URL 的分隔符 “/”。

2.2 自定義URL參數(shù)類型轉(zhuǎn)換器

除了 Django 定義的簡單類型,我們還可以自定義參數(shù)類型轉(zhuǎn)換器來支持更為復(fù)雜的 URL 場景。比如前面的 int 類型并不支持負(fù)整數(shù),我希望開發(fā)一個能匹配正負(fù)數(shù)的類型,具體的步驟如下:

hello_app/urls.py 中定義一個 SignInt 類。該類有一個固定屬性 regex,用于匹配動態(tài)值;兩個固定方法:to_python() 方法和 to_url() 方法:

# hello_app/urls.py

class SignInt:
    regex = '-*[0-9]+'

    def to_python(self, value):
        # 將匹配的value轉(zhuǎn)換成我們想要的類型
        return int(value)

    def to_url(self, value):
        # 反向生成url時候回用到
        return value

注冊該定義的轉(zhuǎn)換器,并給出一個簡短的名字,比如 sint:

# hello_app/urls.py

from django.urls import converters, register_converter

register_converter(SignInt, 'sint')

...

最后,我們就可以在 URLconf 中使用該類型來配置動態(tài)的 URL 表達(dá)式:

# hello_app/urls.py

urlpatterns = [
    path('articles/<sint:signed_num>/', views.signed_convert),
]

# hello_app/views.py
def signed_convert(request, signed_num, **kwargs):
    return HttpResponse('hello, 自定義類型轉(zhuǎn)換器,獲取參數(shù)={}\n'.format(signed_num))

啟動 Django 服務(wù)后,執(zhí)行相關(guān)請求,可以看到 Django 的路由系統(tǒng)能成功匹配到帶負(fù)數(shù)和正數(shù)的 URL:

[root@server ~]# curl http://127.0.0.1:8881/hello/articles/1998/
hello, 自定義類型轉(zhuǎn)換器,獲取參數(shù)=1998
[root@server ~]# curl http://127.0.0.1:8881/hello/articles/-1998/
hello, 自定義類型轉(zhuǎn)換器,獲取參數(shù)=-1998

2.3 使用正則表達(dá)式

上面是比較簡單的 URLconf 配置形式,Django 框架中可以使用正則表達(dá)式來進(jìn)一步擴(kuò)展動態(tài) URL 的配置,此時 urlpatterns 中的不再使用 path 方法而是支持正則表達(dá)式形式的 re_path 方法。此外,在 Python 的正則表達(dá)式中支持對匹配結(jié)果進(jìn)行重命名,語法格式為:(?P<name>pattern),其中 name 為該匹配的名稱,pattern 為匹配的正則表達(dá)式。 這樣我們可以有如下的 URLconf 配置:

# hello_app/urls.py
from django.urls import re_path

from . import views

urlpatterns = [
    re_path('articles/(?P<year>[0-9]{4})/', views.year_archive),
    re_path('articles/(?P<year>[0-9]{4})/(?P<month>0[1-9]|1[0-2])/', views.month_archive),
    re_path('articles/(?P<year>[0-9]{4})/(?P<month>0[1-9]|1[0-2])/(?P<title>[a-zA-Z0-9-_]+)/', views.article_title),
]

注意:這里使用正則表達(dá)式的 URL 匹配和前面的普通的動態(tài) URL 匹配有一個非常重要的區(qū)別,基于正則表達(dá)式的URL 匹配一旦匹配成功就會直接跳轉(zhuǎn)到視圖函數(shù)進(jìn)行處理,而普通的動態(tài) URL 匹配則會找到最長匹配的動態(tài) URL,然后再進(jìn)入相應(yīng)的視圖函數(shù)去處理:

[root@server ~]# curl http://127.0.0.1:8881/hello/articles/1998/12/test
hello, 1998 archive

可以看到,這里并沒有匹配到第三個 re_path 的 URL 配置,而是直接由第一個 re_path 的視圖函數(shù)進(jìn)行了處理。

2.4 URLconf 傳遞額外參數(shù)

在前面的 URLconf 配置中,我們的 re_path 方法中只傳遞兩個參數(shù),分別是設(shè)計(jì)的路由以及對應(yīng)的視圖函數(shù)。我們可以看看 Django-2.2.10 中的 path 和 re_path 方法的源代碼:

# django/urls/conf.py
# ...

def _path(route, view, kwargs=None, name=None, Pattern=None):
    if isinstance(view, (list, tuple)):
        # For include(...) processing.
        pattern = Pattern(route, is_endpoint=False)
        urlconf_module, app_name, namespace = view
        return URLResolver(
            pattern,
            urlconf_module,
            kwargs,
            app_name=app_name,
            namespace=namespace,
        )
    elif callable(view):
        # view是函數(shù)
        pattern = Pattern(route, name=name, is_endpoint=True)
        return URLPattern(pattern, view, kwargs, name)
    else:
        raise TypeError('view must be a callable or a list/tuple in the case of include().')


path = partial(_path, Pattern=RoutePattern)
re_path = partial(_path, Pattern=RegexPattern)

可以看到,除了route 和 view 外,我們還有 name、kwargs、Pattern 參數(shù)(比較少用)。其中 name 參數(shù)表示的是 route 匹配到的 URL 的一個別名,而 kwargs 是我們可以額外傳給視圖函數(shù)的參數(shù):

# hello_app/urls.py
...

urlpatterns = [
    re_path('articles/(?P<year>[0-9]{4})/', views.year_archive, {'hello': 'app'}),
]

# hello_app/views.py
def year_archive(request, *args, **kwargs):
    return HttpResponse('hello, year archive, 額外參數(shù)={}\n'.format(kwargs))

啟動 Django 服務(wù)后,我們請求對應(yīng)的服務(wù),可以看到除了 URL 中匹配的 year 參數(shù)外,還有 re_path 中額外傳遞的參數(shù),最后都被視圖函數(shù)中的 **kwargs 接收:

[root@server ~]# curl http://127.0.0.1:8881/hello/articles/1998/
hello, year archive, 額外參數(shù)={'year': '1998', 'hello': 'app'}

2.5 從 HttpRequest 中獲取參數(shù)

從 HttpRequest 中獲取參數(shù)是我們進(jìn)行 Web 開發(fā)中最常用的一種方式。對于 Django 的視圖函數(shù)來說,HTTP 請求的數(shù)據(jù)被 HttpRequest 實(shí)例化后傳到了視圖函數(shù)的第一個參數(shù)中。為了能觀察相關(guān)信息,我們修改請求的視圖函數(shù):

@csrf_exempt
def hello_view(request, *args, **kwargs):
    # 在第三次使用表單上傳包括文件數(shù)據(jù)時,需要request.GET和request.POST操作,不然會拋異常
    params = "request.GET={}\n".format(request.GET)
    params += "request.POST={}\n".format(request.POST)
    params += "request.body={}\n".format(request.body)
    params += "request.FILES={}\n".format(request.FILES)

    return HttpResponse(params)

我們測試如下 3 種 HTTP 請求,分別為 GET 請求、POST 請求 和帶文件參數(shù)的請求,結(jié)果如下:

[root@server ~]# curl -XGET "http://127.0.0.1:8881/hello/world/?a=xxxx&b=yyyy" 
request.GET=<QueryDict: {'a': ['xxxx'], 'b': ['yyyy']}>
request.POST=<QueryDict: {}>
request.body=b''
request.FILES=<MultiValueDict: {}>

[root@server ~]# curl -XPOST -d "username=shen&password=shentong" "http://127.0.0.1:8881/hello/world/?a=xxxx&b=yyyy" 
request.GET=<QueryDict: {'a': ['xxxx'], 'b': ['yyyy']}>
request.POST=<QueryDict: {'username': ['shen'], 'password': ['shentong']}>
request.body=b'username=shen&password=shentong'
request.FILES=<MultiValueDict: {}>

# 本次請求中,需要去掉request.GET和request.POST操作語句,不然請求會報(bào)錯
[root@server ~]# curl -XPOST -F "username=shen&password=shentong" "http://127.0.0.1:8881/hello/world/?a=xxxx&b=yyyy" -F "files=@/root/upload_file.txt"
request.body=b'------------------------------68c9ede00e93\r\nContent-Disposition: form-data; name="username"\r\n\r\nshen&password=shentong\r\n------------------------------68c9ede00e93\r\nContent-Disposition: form-data; name="files"; filename="upload_file.txt"\r\nContent-Type: text/plain\r\n\r\nupload file test\n\r\n------------------------------68c9ede00e93--\r\n'
request.FILES=<MultiValueDict: {'files': [<InMemoryUploadedFile: upload_file.txt (text/plain)>]}>

可以看到,跟在 “?” 后的參數(shù)數(shù)據(jù)會保存到 request.GET 中,這也是 GET 請求帶參數(shù)的方式。對于 POST 請求的傳參,數(shù)據(jù)一般會保存在 request.POSTrequest.body 中。對于最后發(fā)送的上傳文件請求,可以看到,文件內(nèi)容的內(nèi)容數(shù)據(jù)是保存到了 request.body 中。

3. 小結(jié)

本節(jié)內(nèi)容我們主要介紹了如何向視圖函數(shù)傳送參數(shù),包括兩種方式:

  1. 通過動態(tài)的 URLconf 配置傳遞參數(shù)到視圖函數(shù)中;

  2. 通過 http 請求帶參數(shù)傳遞給視圖函數(shù)。至此,Django 中的路由系統(tǒng)和視圖函數(shù)已經(jīng)介紹完畢。接下來會介紹 Django 中的模板系統(tǒng)。