日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Django視圖層與模板層實例詳解_python

作者:愛新覺羅吉星 ? 更新時間: 2022-10-30 編程語言

theme: channing-cyan

網頁偽靜態

將動態網頁偽裝成靜態網頁,可以提升網頁被搜索引擎檢索道德概率

表現形式為:網址看著像是一個具體的文件路徑例如:http://127.0.0.1:8001/admin/login/

path('index.html', views.index)

視圖層

1.視圖函數的返回值問題

當我們在views.py定義的視圖函數不設置返回值時,可以看到django報了以下錯誤:

報錯信息:

The view app01.views.home didn't return an HttpResponse object. It returned None instead.

視圖app01.views.home沒有返回HttpResponse對象。它返回None。

由此我們可以猜測一個結論:視圖函數必須返回一個HttpResponse對象 我們ctrl+左鍵進入HttpResponse可以發現它是一個類:

class HttpResponse(HttpResponseBase):
	pass

可是視圖函數還可以返回render和redirect對象啊,我們進入到這兩個函數中一探究竟:

def render(...):
    pass
    return HttpResponse(content, content_type, status)

render函數返回值也是HttpResponse對象。 再來看看redirect:

def redirect(to, *args, permanent=False, **kwargs):
    redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
    return redirect_class(resolve_url(to, *args, **kwargs))

redirect函數返回值也是HttpResponse對象。

由此可見,views.py中的視圖函數都必須返回一個HttpResponse對象

2.視圖函數返回json格式數據

需求:將字典數據序列化成json字符串傳給前端::

方法1:利用json模塊

def home(request):
    import json
    user_dict = {'name': 'jason老師', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
    json_user_dict = json.dumps(user_dict, ensure_ascii=False)
    return render(request, 'home.html', json_user_dict)

方法2:利用JsonResponse

from django.http import JsonResponse
def home(request):
    JsonResponse(user_dict)  # 

只用一行代碼就頂替了上述方法三行代碼,非常好用。但有個問題,JsonResponse沒有ensure_ascii參數,也就意味著我們暫時無法阻止漢字編碼。想要解決這個問題,主要我們查看JsonResponse的源碼:

class JsonResponse(HttpResponse):
    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                 json_dumps_params=None, **kwargs):
        if json_dumps_params is None:
            json_dumps_params = {}
        kwargs.setdefault('content_type', 'application/json')
        data = json.dumps(data, cls=encoder, **json_dumps_params)
        super().__init__(content=data, **kwargs)

可以看到JsonResponse內部是有json.dumps方法的,但這個方法需要傳一些特殊的參數:

**json_dumps_params。這個參數用來接收多余的關鍵字參數并將其打散成一個個的k:v鍵值對。而這些關鍵字需要我們當做json_dumps_params的值,以字典的形式傳入。

于是:

JsonResponse(user_dict, json_dumps_params={'ensure_ascii':False})

這就相當于我們設置了**'ensure_ascii':False** 但是設置這個參數的過程屬實有點坎坷~~

除了字典類型,其他容器類型也可以被序列化,不過要指定safe參數為False

3.form表單攜帶文件數據

form表單需要設置的參數:

<form method="post" enctype="multipart/form-data">
</form>

后端獲取文件代碼:

files = request.FILES  # 后端接收文件數據只能用FILES方法,不能用POST

4.FBV與CBV

FBV:基于函數的視圖

# views.py
def home(request):
    return render(request, 'home.html')
# urls.py
path('home/', views.home)

CBV:基于類的視圖 CBV會根據請求方式的不同自動匹配類中定義的方法并自動執行

# views.py
from django impost views
class MyView(views.View):
    def get(self, request):
        return HttpResponse('我是CBV的get方法')
    def post(self, request):
        return HttpResponse('我是CBV的post方法')
# urls.py
path('func/', views.MyView.as_view())

5.CBV源碼分析

源碼分析入口:

path('func/', views.MyView.as_view())

1.綁定給類的as_view()方法

    def as_view(...):
          def view(...):
              pass
          return view

此時路由匹配代碼的本質:path('func/', views.view())

由此可見,CBV與FBV路由匹配的原理是一樣的

2.path('func/', views.view())?? ?

?? ?這句代碼的意思是:只要我們訪問了func地址,會立即執行后面的views.view()

3.進入view()函數:

    def view(request, *args, **kwargs):
        self = cls(**initkwargs)    # 這里的cls使我們自己寫的類MyView  self是MyView實例化出來的

對象obj ? 這一句相當于 obj = MyView()

? ? ? ? return self.dispatch(request, *args, **kwargs) ?# 這一句相當于obj.dispatch()

4.進入dispatch函數

    def dispatch(self, request, *args, **kwargs):  
    # dispatch是綁定給對象的方法,self相當于是我們前文提到的obj
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(),self.http_method_not_allowed)
           # 反射  通過請求字符串去調用真正的請求方法   這里的請求是post所以handler是post
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)  # 即post(request, *args, **kwargs)
        # 此時 view()函數的返回值為: 
         #  def view(request, *args, **kwargs):
         #        return self.post(request, *args, **kwargs)

模板層

1.模板語法傳值

方式1:指名道姓地傳值。好處是不浪費資源,壞處是值過多時不方便

def home(request):
    name = 'kevin'
    age = 19
    return render(request, 'home.html', {'name':name, 'age': age})

方式2:關鍵字locals()。可以將整個視圖函數名稱空間中所有的名字全部傳入,簡單快捷,壞處是有冗余

def home(request):
    name = 'kevin'
    age = 19
    return render(request, 'home.html', locals())

2.模板語法傳值的范圍

1.基本數據類型都可以傳遞

2.函數名的傳遞會自動加括號執行并將結果展示到頁面上(注意函數如果有參數則不會執行也不會展示,模板語法不支持參數)

3.類名的傳遞也會自動加括號調用并將實例化出的對象展示到頁面上(模板語法會自動判斷每一個名字是否能被加括號調用,如果可以則自動調用)

4.對象的傳遞可以直接用句點符點出對象的屬性

5.django的模板語法在操作容器類型時只能用句點符操作(操作列表用 .數字 的形式)

3.模板語法值過濾器

過濾器類似于python中的內置函數

    <p>統計長度:{{ s|length }}</p>
    <p>加法運算:{{ s|add:'NB' }}</p>
    <p>文件大小:{{ file_size|filesizeformat }}</p>
    <p>數據切片:{{ s|slice:'3' }}</p>
    <p>字符截取:{{ s|truncatechars:3 }}</p>		# 以字符為單位 多出的部分用...代替
    <p>單詞截取:{{ words|truncatewords:3 }}</p>    #以單詞為單位 多出的部分用...代替
    <p>語法轉義:{{ html_tag|safe }}</p>		# 識別字符串中的html標簽 并渲染(默認是不識別)
#html默認不識別后端傳過來的字符串標簽,指定safe可以讓其識別并渲染
#除了在傳給前端之后讓前端識別 我們也可以在后端處理之后再傳給前端,這樣前端就不用識別了(意味著html頁面上的數據不一定非要在html文件中編寫了 也可以通過后端傳入)
    from django.utils.safestring import mark_safe
        script_tag1 = '<script>alert(666)</script>'
        res = mark_safe(script_tag1)  # 直接把res傳給前端

'''
django模板語法中的符號就兩個 一個{{}} 一個{%%}
	需要使用數據的時候 {{}}
	需要使用方法的時候 {%%}
'''  

4.模板語法標簽(類似于python中的流程控制)

if 標簽:

{% if 條件 %} ?條件一般是后端傳過來的數據 ?直接寫名字使用即可
?? ?條件成立執行的代碼
{% elif 條件1 %}
?? ?條件1成立執行的代碼?? ?
{% else %}
?? ?條件都不成立執行的代碼
{% endif %}

for 標簽

{% for i in f %}
? ? {% if forloop.first %}
? ? ? ? <p>這是第一次</p>
? ? {% elif forloop.last %}
? ? ? ? <p>這是最后一次</p>
? ? {% else %}
? ? ? ? <p>啥也不是{{ i }}</p>
? ? {% endif %}
?? ?{% empty %}
? ? ?? ?<p>你給我的是個空 怎么for循環呢</p>
{% endfor %}

for循環可用的一些參數

Variable Description
forloop.counter 當前循環的索引值(從1開始)
forloop.counter0 當前循環的索引值(從0開始)
forloop.revcounter 當前循環的倒序索引值(從1開始)
forloop.revcounter0 當前循環的倒序索引值(從0開始)
forloop.first 當前循環是不是第一次循環(布爾值)
forloop.last 當前循環是不是最后一次循環(布爾值)
forloop.parentloop 本層循環的外層循環

5.自定義標簽函數、過濾器、inclusion_tag

如果想實現自定義,必須先做以下幾件事

1.在應用下創建一個名為templatetags的文件夾 2.在該文件夾下創建任意名稱的.py文件 3.在該py文件內編寫自定義相關代碼

from django.template import Library
	register = Library()

自定義過濾器

@register.filter(name='myfilter')
    def my_add(a, b):
        return a + b

自定義標簽函數

@register.simple_tag(name='mt')
    def func(a, b, c, d):
        return a + b + c + d

自定義inclusion_tag

@register.inclusion_tag(filename='it.html')
    def index(n):
        html = []
        for i in range(n):
            html.append('第%s頁'%i)
        return locals()

自定義標簽的使用

{% load mytag %}
{{ i|myfilter:1 }}
{% mt 1 2 3 4 %}
{% index 10 %}

6.模板的繼承

{% extends 'html文件名' %}

{% block 名字 %}
?? ?模板內容(將要被繼承的部分)?? ? ? ??? ?
{% endblock %}

{% block 名字 %}
?? ?子板內容
{% endblock %}
一般情況下母板中至少應該有三個區域使得擴展性更高!!! ??? ?css content js
{% block css %}
{% endblock %}

{% block content %}
{% endblock %}

{% block js %}
{% endblock %}

子板中還可以使用母板的內容 ?{{ block.super }}

7.模板的導入

將html頁面的某個部分以模塊的形式導入

{% include 'menu.html' %}

原文鏈接:https://juejin.cn/post/7138751045777227806

欄目分類
最近更新