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

全部開(kāi)發(fā)者教程

Django 入門教程

課程導(dǎo)學(xué)
Django 慕課教程使用指南
Django開(kāi)發(fā)實(shí)戰(zhàn)
35 開(kāi)發(fā)實(shí)戰(zhàn)

Django 的 TemplateView 類視圖詳解

接下來(lái)的兩個(gè)小節(jié),主要介紹 Django 中的幾個(gè)常用的視圖類,我們統(tǒng)一按照這樣的方式進(jìn)行講解:首先使用該視圖類,完成一個(gè)簡(jiǎn)單的例子,熟悉該類的使用;接下來(lái)深入源碼分析,完整梳理該視圖類的實(shí)現(xiàn)過(guò)程,順帶梳理 Django 中和該類相關(guān)的源碼 。

1. TemplateView 類介紹和使用

TemplateView 視圖類是用來(lái)渲染給定的模板文件,其上下文字典包含從 URL 中捕獲的參數(shù)。首先來(lái)看看最簡(jiǎn)單的模板渲染示例:

準(zhǔn)備模板文件,放到 template 目錄,在 settings.py 中需要配置好模板 (TEMPLATES) 相關(guān)的參數(shù):

[root@server first_django_app]# cat templates/test.html 
<p>{{ content }}</p>
<div>{{ spyinx.age }}</div>

準(zhǔn)備好類視圖,處理相關(guān) HTTP 請(qǐng)求,這里使用今天要學(xué)習(xí)的 TemplateView 類:

class TestTemplateView(TemplateView):
    template_name = 'test.html'
    
    @csrf_exempt
    def dispatch(self, request, *args, **kwargs):
        return super(TestTemplateView, self).dispatch(request, *args, **kwargs)

配置相應(yīng)的 URLConf:

context_data = {'content':'正文1', 'spyinx':{'age': 29}}

urlpatterns = [
    path('test_template_view/',
         views.TestTemplateView.as_view(extra_context=context_data), 
         name='test_template_View')
]

啟動(dòng) first_django_app 工程,然后使用 curl 命令簡(jiǎn)單測(cè)試,發(fā)送 GET 請(qǐng)求:

# 啟動(dòng)first_django_app工程,監(jiān)聽(tīng)8888端口
(django-manual) [root@server first_django_app]# python manage.py runserver 0.0.0.0:8888
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
April 16, 2020 - 12:27:49
Django version 2.2.11, using settings 'first_django_app.settings'
Starting development server at http://0.0.0.0:8888/
Quit the server with CONTROL-C.

# 打開(kāi)xshell另一個(gè)窗口,使用curl發(fā)送get請(qǐng)求
[root@server ~]# curl http://127.0.0.1:8888/hello/test_template_view/
<p>正文1</p>
<div>29</div>
# 這個(gè)報(bào)405錯(cuò)誤,不支持POST請(qǐng)求
[root@server ~]# curl -XPOST http://127.0.0.1:8888/hello/test_template_view/
[root@server ~]#

可以看到,我們只是指定了 template_name 屬性,連對(duì)應(yīng)的請(qǐng)求函數(shù)都沒(méi)寫 (寫的 dispatch() 函數(shù)只是為了能執(zhí)行POST請(qǐng)求,避免 csrf 報(bào)錯(cuò)),只是繼承一下這個(gè)視圖類 (TemplateView) 能處理 GET 請(qǐng)求,并能返回渲染的模板,對(duì)一些情況來(lái)說(shuō)是很方便的,節(jié)省了一些代碼。注意的是,其他請(qǐng)求方式不行,因?yàn)?TemplateView 內(nèi)部只實(shí)現(xiàn)了 get() 方法,所以只能處理 GET 請(qǐng)求。

上面的 context_data 是自定義的,現(xiàn)在我們來(lái)從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù),動(dòng)態(tài)填充模板內(nèi)容。同樣是涉及到模板視圖,所以可以通過(guò) TemplateView 類來(lái)實(shí)現(xiàn)。

首先準(zhǔn)備新的模板文件 test.html。這個(gè)模板頁(yè)面使用表格分頁(yè)顯示會(huì)員數(shù)據(jù),查詢的數(shù)據(jù)表是我們前面多次實(shí)驗(yàn)的 member 表。

<html>
<head>
<style type="text/css">
    .page{
       margin-top: 10px;
       font-size: 14px;
    }

    .member-table {
       width: 50%;
       text-align: center;
    }
</style>
</head>
<body>

<p>會(huì)員信息-第{{ current_page }}頁(yè), 每頁(yè){{ page_size }}條, 總共{{ sum }}條</p>
<div>
<table border="1" class="member-table">
  <thead>
  <tr>
    <th>姓名</th>
    <th>年齡</th>
    <th>性別</th>
    <th>職業(yè)</th>
    <th>所在城市</th>
  </tr>
  </thead>
  <tbody>
  {% for member in members %}
  <tr>
    <td>member.name</td>
    <td>member.age</td>
    {% if member.sex == 0 %}
    <td></td>
    {% else %} 
    <td></td>
    {% endif %}
    <td>member.occupation</td>
    <td>member.city</td>
  </tr>
  {% endfor %}
   </tbody>
</table>
<div >
<div class="page">
</div>
</div>
</div>

</body>

</html>

修改上面的視圖函數(shù),分頁(yè)查詢 Member 表中的數(shù)據(jù):

class TestTemplateView(TemplateView):
    template_name = 'test.html'
    def get(self, request, *args, **kwargs):
        params = request.GET
        page = int(params.get('page', 1))
        size = int(params.get('size', 5))
        data = {}
        data['sum'] = Member.objects.all().count()
        members = Member.objects.all()[(page - 1) * size:page * size]
        data['current_page'] = page
        data['page_size'] = size
        data['members'] = members
        return self.render_to_response(context=data)

這里我們使用了前面學(xué)習(xí)的 Django ORM 模型,獲取 member 表中的數(shù)據(jù),然后使用 TemplateView 中的模板渲染方法 render_to_response() 返回渲染后的 HTML 文本給到客戶端。

測(cè)試結(jié)果如下,以下兩張圖片是設(shè)置了不同的查詢參數(shù)(當(dāng)前頁(yè)碼和頁(yè)大小),可以看到查詢參數(shù)是起了效果的:

圖片描述

圖片描述

2. TemplateView 類深入分析

2.1 TemplateResponse 和 SimpleTemplateResponse

很早之前,我們介紹過(guò) HttpResponse,它用于生成 HTTP 請(qǐng)求的相應(yīng),返回的內(nèi)容由 content 屬性確定,主要是用于提供靜態(tài)內(nèi)容顯示。TemplateResponse 對(duì)象則不同,它允許裝飾器或中間件在通過(guò)視圖構(gòu)造響應(yīng)之后修改響應(yīng)內(nèi)容。TemplateResponse 對(duì)象保留視圖提供的、用于計(jì)算響應(yīng)內(nèi)容的模板和上下文數(shù)據(jù),直到最后需要時(shí)才計(jì)算相應(yīng)內(nèi)容并返回響應(yīng)。

SimpleTemplateResponse 對(duì)象是 TemplateResponse 的父類,兩者功能和使用基本類似,幾乎是一致的。

# 源碼位置: django/template/response.py
class TemplateResponse(SimpleTemplateResponse):
    rendering_attrs = SimpleTemplateResponse.rendering_attrs + ['_request']

    def __init__(self, request, template, context=None, content_type=None,
                 status=None, charset=None, using=None):
        super().__init__(template, context, content_type, status, charset, using)
        self._request = request

SimpleTemplateResponse 是繼承自 HttpResponse 對(duì)象,并做了諸多擴(kuò)展。它的重要屬性和方法如下:

重要屬性

  • template_name:模板文件名;
  • context_data : 上下文字典數(shù)據(jù);
  • rendered_content:指使用當(dāng)前的模板和上下文字段數(shù)據(jù)已渲染的響應(yīng)內(nèi)容。一個(gè)作為屬性的方法,調(diào)用該屬性時(shí)啟動(dòng)渲染過(guò)程;
  • is_rendered: 布爾類型,判斷響應(yīng)內(nèi)容是否已經(jīng)被渲染。

重要方法

  • __init__(template, context=None, content_type=None, status=None, charset=None, using=None):類初始化函數(shù),各參數(shù)的含義與 HttpResponse 相同;

  • resolve_context(context):預(yù)處理會(huì)被用于模板渲染的上下文數(shù)據(jù) ;

  • resolve_template(template):接收(如由 get_template() 返回的) backend-dependent 的模板對(duì)象、模板名字、或者多個(gè)模板名字組成的列表。返回 backend-dependent 的模板對(duì)象實(shí)例,后面用于渲染;

  • add_post_render_callback():添加渲染完成后的回調(diào)函數(shù),如果該方法運(yùn)行時(shí)渲染已完成,回調(diào)函數(shù)會(huì)被立即調(diào)用;

  • render():設(shè)置 response.content 的結(jié)果為 SimpleTemplateResponse.rendered_content 的值,執(zhí)行所有渲染后的回調(diào)函數(shù),返回所有響應(yīng)對(duì)象。render() 只會(huì)在第一次調(diào)用時(shí)起作用。在隨后的調(diào)用中,它將返回從第一個(gè)調(diào)用獲得的結(jié)果。

實(shí)驗(yàn)部分:

我們來(lái)使用 TemplateResponse 來(lái)完成一個(gè)簡(jiǎn)單的案例。同樣是在 first_django_app 工程中,準(zhǔn)備的代碼內(nèi)容參考如下,分別是模板文件、視圖文件以及 URLConf 配置文件。

# 模板文件: template/test.html
<p>{{ content }}</p>
<div>{{ spyinx.age }}</div>

# URLConf配置文件: hello_app/urls.py
urlpatterns = [
    path('test-cbv/', views.TestView.as_view(), name="test-cbv")
]

# 視圖文件: hello_app/views.py
def my_render_callback(response):
    # Do content-sensitive processing
    print('執(zhí)行渲染完成后的回調(diào)函數(shù),渲染內(nèi)容:\n{}\n是否完成渲染:{}'.format(response.rendered_content, response.is_rendered))

class TestView(View):

    def get(self, request, *args, **kwargs):
        response = TemplateResponse(request, 'test.html', context={'content': '正文1', 'spyinx':{'age': 29}})
        response.add_post_render_callback(my_render_callback)
        return response

我們?cè)谠浦鳈C(jī)上使用 curl 命令發(fā)送 HTTP 請(qǐng)求,觀察結(jié)果:

# 使用runserver命令啟動(dòng)first_django_app工程
...

# 打開(kāi)另一個(gè)xshell窗口,使用curl命令發(fā)送請(qǐng)求結(jié)果
[root@server ~]# curl http://127.0.0.1:8888/hello/test-cbv/
<p>正文1</p>
<div>29</div>

# 回到上一個(gè)窗口,查看打印結(jié)果
(django-manual) [root@server first_django_app]# python manage.py runserver 0.0.0.0:8888
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
April 16, 2020 - 07:10:18
Django version 2.2.11, using settings 'first_django_app.settings'
Starting development server at http://0.0.0.0:8888/
Quit the server with CONTROL-C.
執(zhí)行渲染完成后的回調(diào)函數(shù),渲染內(nèi)容:
<p>正文1</p>
<div>29</div>

是否完成渲染:True
[16/Apr/2020 07:10:38] "GET /hello/test-cbv/ HTTP/1.1" 200 29

2.2 ContextMixin 和 TemplateResponseMixin

接下來(lái),我們查看下 Django 提供的兩個(gè) mixin:ContextMixin 和 TemplateResponseMixin。其內(nèi)容比較簡(jiǎn)單,源碼如下:

# 源碼位置:django/views/generic/base.py

class ContextMixin:
    """
    A default context mixin that passes the keyword arguments received by
    get_context_data() as the template context.
    """
    extra_context = None

    def get_context_data(self, **kwargs):
        kwargs.setdefault('view', self)
        if self.extra_context is not None:
            kwargs.update(self.extra_context)
        return kwargs
    
class TemplateResponseMixin:
    """A mixin that can be used to render a template."""
    template_name = None
    template_engine = None
    response_class = TemplateResponse
    content_type = None

    def render_to_response(self, context, **response_kwargs):
        """
        Return a response, using the `response_class` for this view, with a
        template rendered with the given context.

        Pass response_kwargs to the constructor of the response class.
        """
        response_kwargs.setdefault('content_type', self.content_type)
        return self.response_class(
            request=self.request,
            template=self.get_template_names(),
            context=context,
            using=self.template_engine,
            **response_kwargs
        )

    def get_template_names(self):
        """
        Return a list of template names to be used for the request. Must return
        a list. May not be called if render_to_response() is overridden.
        """
        if self.template_name is None:
            raise ImproperlyConfigured(
                "TemplateResponseMixin requires either a definition of "
                "'template_name' or an implementation of 'get_template_names()'")
        else:
            return [self.template_name]

ContextMixin 比較簡(jiǎn)單,只提供了一個(gè)屬性 extra_context 和一個(gè)方法 get_context_data(),它主要的功能是根據(jù)額外提供的參數(shù),組成新的上下文字典,調(diào)用 get_context_data() 方法即可實(shí)現(xiàn)。

TemplateResponseMixin 是用來(lái)渲染模板的,它的屬性與方法如下:

屬性

  • template_name:模板文件名;
  • template_engine: 模板引擎;
  • response_class: 返回的 Response,默認(rèn)是 TemplateResponse;
  • content_type:返回客戶端的數(shù)據(jù)類型。

方法

  • render_to_response():默認(rèn)直接調(diào)用 TemplateResponse(),完成模板渲染后返回響應(yīng)給客戶端;
  • get_template_names():獲取模板名稱,返回列表的形式;如果沒(méi)有設(shè)置 template_name 屬性值,則會(huì)報(bào)錯(cuò)。因此對(duì)于繼承該 mixin 對(duì)象的子類,必須要設(shè)置 template_name 屬性值。

Mixin 的特點(diǎn)就是功能簡(jiǎn)單,它們可以混合加到其他類中,那么其他類就具備這些 Mixin 的功能,組合得到一個(gè)更高級(jí)的類。同樣我們?cè)谇耙恍」?jié)實(shí)驗(yàn)的基礎(chǔ)上改造下 views.py 中的內(nèi)容,如下:

class TestView(TemplateResponseMixin, View):
    template_name = 'test.html'
    def get(self, request, *args, **kwargs):
        return self.render_to_response(context={'content': '正文1', 'spyinx': {'age': 29}})

這里我們額外繼承 TemplateResponseMixin 類。首先需要添加 template_name 屬性,指定要渲染的模板文件,然后調(diào)用從 TemplateResponseMixin 中繼承過(guò)來(lái)的 render_to_response() 方法并返回。從源碼角度來(lái)看,這個(gè)視圖實(shí)現(xiàn)的功能和上一個(gè)小節(jié)中直接返回 TemplateResponse 實(shí)例是一樣的。

# 啟動(dòng) first_django_app 工程
...

# 打開(kāi)xshell另一個(gè)窗口,發(fā)送http請(qǐng)求
[root@server first_django_app]# curl http://127.0.0.1:8888/hello/test-cbv/
<p>正文1</p>
<div>29</div>

2.3 TemplateView 類

介紹完上面那些基礎(chǔ)的類以及 Mixin 后,終于可以看 TemplateView 的代碼了,我們發(fā)現(xiàn)它其實(shí)就是 View 類中混入了 ContextMixin 和 TemplateResponseMixin,此外還多了一個(gè) get 函數(shù),對(duì)應(yīng)著 get 請(qǐng)求。

# 源碼路徑 django/views/generic/base.py

class TemplateView(TemplateResponseMixin, ContextMixin, View):
    """
    Render a template. Pass keyword arguments from the URLconf to the context.
    """
    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

就是這個(gè) get 請(qǐng)求方法讓我們前面第一個(gè)實(shí)驗(yàn)中,只需要寫對(duì)應(yīng)的模板文件名,另外傳遞 extra_context 就可以渲染模板并返回。注意,這個(gè) extra_context 屬性是繼承自 ContextMixin 對(duì)象,它的賦值過(guò)程是走的 View 類?,F(xiàn)在可以通過(guò)代碼分析一下這個(gè)復(fù)制過(guò)程,加深印象。

首先看 as_view() 函數(shù)傳參部分:

context_data = {'content':'正文1', 'spyinx':{'age': 29}}

urlpatterns = [
    path('test_template_view/',
         views.TestTemplateView.as_view(extra_context=context_data), 
         name='test_template_View')
]

as_view() 方法的源碼如下。傳進(jìn)來(lái)的參數(shù)在 initkwargs 中,最后在 View 類中使用該字典參數(shù)初始化實(shí)例。

# 源碼位置: django/views/generic/base.py

    @classonlymethod
    def as_view(cls, **initkwargs):
        # ...
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            # ...
            
        # ...
        return view

最后來(lái)看 View 的初始化函數(shù)??梢钥吹竭@些初始化的參數(shù)會(huì)作為類的屬性進(jìn)賦值,使用的是 setattr() 方法,這樣我們?cè)?as_view() 方法中傳遞的 extra_context 參數(shù)就被成功賦值到 extra_context 屬性上了。

class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    # ...

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in kwargs.items():
            setattr(self, key, value)

其實(shí)通過(guò)了解這些源代碼后,我們能很好得理解前面使用 TemplateView 類做的一些測(cè)試結(jié)果。目前來(lái)看,我們接觸到的這部分源代碼還是比較簡(jiǎn)單易懂的,官方網(wǎng)站對(duì) Django 中出現(xiàn)的許多常用類都做了詳細(xì)的介紹,我們只需要不停的學(xué)習(xí)源代碼、參考官方的文檔、堅(jiān)持不懈,一定能達(dá)到精通 Django 的目的。

3. 小結(jié)

本小節(jié)中,我們先介紹了 TemplateView 的幾種常見(jiàn)用法。接下來(lái)開(kāi)始深入 Django 源碼,分析 TemplateView 繼承的兩個(gè) mixin,最后通過(guò)整個(gè)源碼分析和測(cè)試,對(duì)于前面 TemplateView 的用法會(huì)理解的更加透徹。