django 之視圖層及模板層 04

路由:視圖函數的內存地址html

視圖層

render方法是Template和Contex兩個對象的組合使用

from django .template import Template,Context
def func1(request):
    res = Template('<h1>{{user}}</h>')
    con=Context({'user':{'username':'zhang','password':123,}})
    return HttpResponse(res.render(con))

JsonResponse對象

JsonResponse是HttpResponse的子類,專門用來生成JSON編碼的響應。前端

# ensure_ascii=False 默認等於True,設置成False,遇到中文再也不進行轉碼,僅僅只是進行序列化,轉換成json形式的字符串
import json
def func(request):
    d={'a':1,'b':3,'c':3,'d':4,'e':'速度發貨!!!!!!!'}
    return HttpResponse(json.dumps(d,ensure_ascii=False),)  #
from django.http import JsonResponse
def func(request):
    d={'a':1,'b':3,'c':3,'d':4,'e':'速度發貨!!!!!!!'}
    l=[1,2,3,4,5,]
   # return JsonResponse(d)  # 加括號是個對象,內部也是基於json.dumps進行的序列化,默認遇到中文也會轉成ASCII編碼,
    # return JsonResponse(d,json_dumps_params={'ensure_ascii':False})  # 遇到中文不轉碼
    return JsonResponse(l,safe=False)  # In order to allow non-dict objects to be serialized set the safe parameter to False.  根據報錯信息,去源碼找到JsonResponse不能序列化其餘數據類型的緣由,就是修改safe=True 爲False,以後就能序列化其餘數據類型(json模塊能序列化的)了

CBV及源碼分析

咱們以前寫過的都是基於函數的view,就叫FBV。還能夠把view寫成基於類的。
FBV:基於函數的視圖
CBV:基於類的視圖python

from django.views import View

class MyLogin(View):
    def get(self,request):
        print('我是MyLogin裏面的get方法')
        return render(request,'login.html')

    def post(self,request):
        print('我是MyLogin裏面的post方法')
        return HttpResponse('post')

    # 路由的書寫 與CBV有點不一樣
    # FBV寫法     路由 >>> 視圖函數內存地址
    url(r'^index/',views.index),
    # CBV寫法
    url(r'^login/',views.MyLogin.as_view())  # views.view  本質也是FBV
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    
     def http_method_not_allowed(self, request, *args, **kwargs):
        logger.warning(
            'Method Not Allowed (%s): %s', request.method, request.path,
            extra={'status_code': 405, 'request': request}
        )
        return http.HttpResponseNotAllowed(self._allowed_methods())
    
    @classonlymethod
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):  # 閉包函數
            self = cls(**initkwargs)  # cls是咱們本身寫的類 MyLogin  self是咱們本身定義的類的對象
            # 在看源碼的時候 你必定要把握住一個順序 對象在查找屬性和方法的時候
            # 先從對象自身找 再去產生對象的類中找 再去類的父類中找
            return self.dispatch(request, *args, **kwargs)
        return view


    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        # 判斷當前請求方式在不在默認的八個方法內
        # 1.先以GET請求爲例
        if request.method.lower() in self.http_method_names:
            # 利用反射去咱們本身定義類的對象中查找get屬性或者是方法  getattr(obj,'get')
            # handler = get方法
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
                return handler(request, *args, **kwargs)  # 調用get方法

CBV 加裝飾器的方式

使用裝飾器裝飾FBV
FBV自己就是一個函數,因此和給普通的函數加裝飾器無差:jquery

def wrapper(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        ret = func(*args, **kwargs)
        end_time = time.time()
        print("used:", end_time-start_time)
        return ret
    return inner


# FBV版添加班級
@wrapper
def add_class(request):
    if request.method == "POST":
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")
    return render(request, "add_class.html")

CBV 加裝飾器的方式django

類中的方法與獨立函數不徹底相同,所以不能直接將函數裝飾器應用於類中的方法 ,咱們須要先將其轉換爲方法裝飾器。json

Django中提供了method_decorator裝飾器用於將函數裝飾器轉換爲方法裝飾器bootstrap

#使用CBV時要注意,請求過來後會先執行dispatch()這個方法,若是須要批量對具體的請求處理方法,如get,post等作一些操做的時候,這裏咱們能夠手動改寫dispatch方法,這個dispatch方法就和在FBV上加裝飾器的效果同樣。後端

給CBV加裝飾器 推薦你使用內置模塊
from django.utils.decorators import method_decorator

# 2.能夠指定給誰裝
# @method_decorator(wrapper,name='post')  # name=... 表示指定給誰裝
# @method_decorator(wrapper,name='dispatch')
class MyLogin(View):
    @method_decorator(wrapper)
    def dispatch(self, request, *args, **kwargs):  # 若是你想在視圖函數執行以前 作一些操做 你能夠在你的CBV中定義dispatch方法來攔截

        return super().dispatch(request,*args,**kwargs)
    # @outter  # 1.直接寫
    # @method_decorator(outter)  # 1.推薦寫法
    def get(self,request):
        print('我是MyLogin裏面的get方法')
        return render(request,'login.html')
    # @outter
    def post(self,request):
        print('我是MyLogin裏面的post方法')
        time.sleep(1)
        return HttpResponse('post')

模板層

模板語法傳值

模板語法

只有兩種書寫格式:
            {{}}  變量相關
            {%%}  邏輯相關

        模板傳值:python基本數據類型所有支持傳值

變量

在Django的模板語言中按此語法使用:{{ 變量名 }}。閉包

當模版引擎遇到一個變量,它將計算這個變量,而後用結果替換掉它自己。 變量的命名包括任何字母數字以及下劃線 ("_")的組合。 變量名稱中不能有空格或標點符號。

點(.)在模板語言中有特殊的含義。當模版系統遇到點("."),它將以這樣的順序查詢:

字典查詢(Dictionary lookup)
屬性或方法查詢(Attribute or method lookup)
數字索引查詢(Numeric index lookup)

注意事項:

  1. 若是計算結果的值是可調用的,它將被無參數的調用。 調用的結果將成爲模版的值。
  2. 若是使用的變量不存在, 模版系統將插入 string_if_invalid 選項的值, 它被默認設置爲'' (空字符串)
# test.py文件
def test(request):
    n=1
    f=1.11
    s='hello baby~'
    l=[1,2,3,4,]
    t=(1,2,3,44,55)
    d={'name':'zhangsan','hobby':'read'}
    se={12,13,14,15,}
    b=False
    def index1():  #給HTML頁面傳遞函數名的時候 模板語法會自動加括號調用該函數 而且將函數的返回值當作展現依據,模板語法不支持函數傳參 也就意味着 你傳給html頁面的只能是不須要傳參調用的函數
        return '都是廢話'
    class Test(object):
        def get_self(self):
            return 'get_self'
    obj = Test()
    return render(request,'test.html',locals())

# 傳類名像函數名同樣,也是加括號調用,實例化一個對象;傳對象,就是對象自己,是類的對象的內存地址;只要是可以加括號調用的 傳遞到html頁面上都會自動加括號調用
<!--test.html文件-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>

</head>
<body>
<p>{{ n }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ l }}</p>
<p>{{ se }}</p>
<p>{{ d }}</p>
<p>{{ b }}</p>
<p>傳函數名:{{ index1 }}</p>
<p>傳函數名:{{ Test }}</p>   
<p>傳函數名:{{ obj }}</p>  
</body>
</html>

過濾器(Filters)

模板語法也給你提供了一些內置的方法 幫你快速的處理數據
過濾器的語法: {{ value|filter_name:參數 }}

例如:{{ name|lower }}會將name變量應用lower過濾器以後再顯示它的值。lower在這裏的做用是將文本全都變成小寫。

注意事項:

1.過濾器支持「鏈式」操做。即一個過濾器的輸出做爲另外一個過濾器的輸入。
2.過濾器能夠接受參數,例如:{{ sss|truncatewords:30 }},這將顯示sss的前30個詞。
3.過濾器參數包含空格的話,必須用引號包裹起來。好比使用逗號和空格去鏈接一個列表中的元素,如:{{ list|join:', ' }}
4.'|'左右沒有空格沒有空格沒有空格

先後端取消轉義(*)

前端
    |safe
後端
from django.utils.safestring import mark_safe
sss2 = "<h2>個人h2標籤</h2>"
res = mark_safe(sss2)
<p>統計長度(若是沒法統計默認返回0):{{ s|length }}</p>
<p>加法運算(內部異常捕獲 支持數字相加 字符串拼接 都不符合返回空):{{ n|add:f }}</p>
<p>切片操做 顧頭不顧尾 也支持步長:{{ l|slice:'0:5:2' }}</p>
<p>判斷是否有值(有值展現值自己 沒值展現默認值):{{ is_value|default:'is_value變量名指向的值爲空' }}</p>
<p>自動轉成文件大小格式:{{ file_size|filesizeformat }}</p>
<p>截取文本內容(字符) 截取五個字符 三個點也算:{{ s|truncatechars:8 }}</p>
<p>截取文本內容(按照空格計算) 截取五個字符 三個點不算 :{{ s1|truncatewords:5 }}</p>
<p>默認狀況下,不會轉換成前端html標籤 :{{sss}}</p>  # 後端傳來的字符串類型的標籤
<p>展現帶有標籤的文本:{{ sss|safe }}</p> 添加safe參數以後能夠轉換後端傳來的字符串標籤
<p>展現帶有標籤的文本:{{ ss|safe }}</p>  後端: ss='<script>alert(123)</script>'

標籤

標籤 邏輯相關
if
for循環

{% for foo in l %}
    {{ forloop }}
    {% if forloop.first %}
        <p>{{ foo }}</p>
    {% elif forloop.last %}
    {% else %}
        <p>{{ foo }}</p>
    {% endif %}
    {% empty %}
        <p>檔for循環的對象爲空的時候走這個!</p>
{% endfor %}

模板語法的取值 只有一種方式 統一採用句點符 (.)

<p>{{ comp_dic.hobby.2.2.age }}</p>
<p>當你的數據是經過比較複雜的點點點獲取到的後續又須要常用 你能夠給該數據起別名 別名只能在with內部使用</p>
{% with comp_dic.hobby.2.2.age as age  %}    
    <p>{{ age }}</p>
    <p>{{ comp_dic.hobby.2.2.age }}</p>
{% endwith %}

自定義過濾器和標籤

自定義過濾器

django支持用戶自定義
必需要先有三部準備
1.在應用名下新建一個名字必須叫templatetags的文件夾
2.在該文件夾內 新建一個任意名稱的py文件
3.在該py文件中 必須先寫下面兩句代碼
from django.template import Library
register = Library()

以後就能夠利用register來自定義過濾器和標籤
# 應用名下templatetag文件夾 mytag.py文件
from django.template import Library
register = Library()
# 自定義過濾器,跟默認的過濾器同樣,最多隻能接受兩個參數
@register.filter(name='xxx') # 給過濾器起名字
def index(a,b):
    return a+b

使用自定義的過濾器,須要先在html頁面上 加載。

<!--test.html文件-->
{% load mytag %}
{{ 1|xxx:99 }}

自定義標籤

# 應用名下templatetag文件夾 mytag.py文件

# 自定義標籤   能夠接受任意多個參數
@register.simple_tag(name='zzz')
def mytag(a,b,c,d):
    return '%s?%s?%s?%s'%(a,b,c,d)
<!--test.html文件-->
{% load mytag %}
{% zzz 'a' 'b' 'c' 'd' %}
<!--test.html文件-->
<p>自定義的過濾器能夠在邏輯語句使用 而自定義的標籤不能夠</p>
{% if 1|xxx:99 %}
    <p>有值</p>
{% else %}
    <p>無值</p>
{% endif %}

自定義inclusion_tag

是一個函數 可以接受外界傳入的參數, 而後傳遞給一個html頁面,頁面上獲取數據 渲染完成以後,將渲染好的頁面放到調用inclusion_tag的地方

# 應用名下templatetag文件夾 mytag.py文件
# 自定義inclusion_tag
@register.inclusion_tag('mytag.html',name='xxx')
def index666(n):
    l = []
    for i in range(n):
        l.append('第%s項'%i)
    return locals()  # 將l直接傳遞給mytag.html頁面
<!--mytag.html文件-->
<!--只作臨時渲染的頁面,因此該頁面的其餘框架部分html代碼就不須要了-->
<ul>
    {% for foo in l %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>
<!--test.html文件-->
<p>自定義inclusion_tag的使用  當你須要使用一些頁面組件的時候 而且該頁面組件須要參數纔可以正常渲染 你能夠考慮使用inclusion_tag</p>
{% load mytag %}
{% xxx 5 %}

模板的繼承

你須要事先在你想要使用的頁面上劃定區域,以後在繼承的時候 ,你就可使用你劃定的區域,也就意味着,若是你不劃定任何區域,那麼你將沒法修改頁面內容。

<!--先在頁面上利用block劃定你之後可能想改的區域-->
{% block content %}
{% endblock %}

<!--繼承以後  就能夠經過名字找到對應的區域進行修改-->
{% extends 'home.html' %}

{% block content %}
<!--修改模板中content區域內容-->
{% endblock %}

模板上的block區域越多 頁面的擴展性越強
建議你一個模板頁面至少有三塊區域:
    css區域
    html代碼區域  能夠設置多個block
    js區域
有了這三塊區域 就可以實現每個頁面都有本身獨立的css和js代碼
{% extends 'home.html' %}  子文件就能夠經過這個方法繼承豬文件的html代碼的格式
{% block css %}
<style>
    p {
        color: green;
    }
</style>
{% endblock %}

{% block content %}
<p>login頁面</p>
{% endblock %}

{% block js %}
<script>
    alert('login')
</script>
{% endblock %}

你還能夠在子頁面上繼續沿用父頁面的內容
        {{ block.super }}

模板的繼承
1.先在你想要繼承的頁面上經過block劃定你未來可能要改的區域
2.在子頁面上先繼承extends
3.利用block自動提示 選擇你想要修改的內容區域

模板的導入

將html頁面當作模塊的直接導入使用
    {% include 'bform.html' %}

下一篇:django之模型層

相關文章
相關標籤/搜索