Django-看到吐

Django框架

Django簡介

一.MVC與MTV模型

mvc:

Web服務器開發領域裏著名的MVC模式,所謂MVC就是把Web應用分爲模型(M),控制器(C)和視圖(V)三層,他們之間以一種插件式的、鬆耦合的方式鏈接在一塊兒,模型負責業務對象與數據庫的映射(ORM),視圖負責與用戶的交互(頁面),控制器接受用戶的輸入調用模型和視圖完成用戶的請求,其示意圖以下所示:php

MTV:

Django的MTV模式本質上和MVC是同樣的,也是爲了各組件間保持鬆耦合關係,只是定義上有些許不一樣,Django的MTV分別是值:css

  • M 表明模型(Model): 負責業務對象和數據庫的關係映射(ORM)。
  • T 表明模板 (Template):負責如何把頁面展現給用戶(html)。
  • V 表明視圖(View): 負責業務邏輯,並在適當時候調用Model和Template。

除了以上三層以外,還須要一個URL分發器,它的做用是將一個個URL的頁面請求分發給不一樣的View處理,View再調用相應的Model和Template,MTV的響應模式以下所示:html

通常是用戶經過瀏覽器向咱們的服務器發起一個請求(request),這個請求回去訪問視圖函數,(若是不涉及到數據調用,那麼這個時候視圖函數返回一個模板也就是一個網頁給用戶),視圖函數調用模型,模型去數據庫查找數據,而後逐級返回,視圖函數把返回的數據填充到模板中空格中,最後返回網頁給用戶。前端

二.Django的下載與基本命令

(1)下載Django

  方式一:在命令行輸入:pip3 install djangopython

    pip install django==1.11.9 -i http://pypi.hustunique.org/simple 指定版本號,指定國內鏡像git

  方式二:用pycharm安裝程序員

  方式三:用pycharm的Terminal的命令行安裝ajax

(2)建立一個django project

django-admin.py startproject mysite  最後接的是文件夾的名字

當前目錄下會生成mysite的工程,目錄結構以下:
正則表達式

  • manage.py ----- Django項目裏面的工具,經過它能夠調用django shell和數據庫等。
  • settings.py ---- 包含了項目的默認設置,包括數據庫信息,調試標誌以及其餘一些工做的變量。
  • urls.py ----- 負責把URL模式映射到應用程序。

(3)在mysite目錄下建立應用

ython manage.py startapp blog

(4)、啓動django項目

python manage.py runserver 8001

這樣咱們的django就啓動起來了!當咱們訪問:http://127.0.0.1:8080/時就能夠看到:
shell

三 基於Django實現的一個簡單示例

1)URL控制器

from django.contrib import admin
from django.urls import path


from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/',views.index),
]

(2)視圖

from django.shortcuts import render

# Create your views here.



def index(request):

    import datetime
    now=datetime.datetime.now()
    ctime=now.strftime("%Y-%m-%d %X")

    return render(request,"index.html",{"ctime":ctime})

(3)模版

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h4>當前時間:{{ ctime }}</h4>

</body>
</html>

四 Django靜態文件配置

新建一個目錄叫:static,咱們的css文件,js文件,圖片文件都放在這下面

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

五 Django請求生命週期

六.命令總結與注意事項:

1.pip3 install dajango==1.11.9

2.django-adimin startportject 項目名字

3.python3 manage.py startapp app名字

4.執行項目:  

- python3 manage.py runserver 127.0.0.1:8080
- python3 manage.py runserver 127.0.0.1
- python3 manage.py runserve    

5.注意事項

- 項目中不能出現中文
- 計算機名字不能是中文
- template路徑須要配置



手動建立Django項目

1.django-adimin startportject 項目名字

2.python3 manage.py startapp app名字

3.執行項目:  

- python3 manage.py runserver 127.0.0.1:8080

4.在settings文件裏配置template路徑:

DIRS: [os.path.join(BASE_DIR,'templates'),]

5.將app的名字加到urls文件裏面

路由層

一 Django中路由的做用

URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於客戶端發來的某個URL調用哪一段邏輯代碼對應執行

典型的例子:

from django.urls import path

urlpatterns = [
    path('articles', views.special),
]
articles這個路由對應着視圖函數中special這個方法,瀏覽器輸入這個連接,就會響應到special這個函數來執行

二 簡單的路由配置

from django.conf.urls import url

urlpatterns = [
     url(正則表達式, views視圖函數,參數,別名),
]
  • 正則表達式:一個正則表達式字符串
  • views視圖函數:一個可調用對象,一般爲一個視圖函數或一個指定視圖函數路徑的字符串
  • 參數:可選的要傳遞給視圖函數的默認參數(字典形式)
  • 別名:一個可選的name參數
from django.urls import path,re_path

from app01 import views

urlpatterns = [
    re_path(r'^articles/2003/$', views.special_case_2003),
    re_path(r'^articles/([0-9]{4})/$', views.year_archive),
    re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

意:

  • 若要從URL 中捕獲一個值,只須要在它周圍放置一對圓括號。

  • 不須要添加一個前導的反斜槓,由於每一個URL 都有。例如,應該是^articles 而不是 ^/articles

  • 每一個正則表達式前面的'r' 是可選的可是建議加上。它告訴Python 這個字符串是「原始的」 —— 字符串中任何字符都不該該轉義

  • urlpatterns中的元素按照書寫順序從上往下逐一匹配正則表達式,一旦匹配成功則再也不繼續

    '''
     一些請求的例子:
    
    /articles/2005/03/ 請求將匹配列表中的第三個模式。Django 將調用函數views.month_archive(request, '2005', '03')。
    /articles/2005/3/ 不匹配任何URL 模式,由於列表中的第三個模式要求月份應該是兩個數字。
    /articles/2003/ 將匹配列表中的第一個模式不是第二個,由於模式按順序匹配,第一個會首先測試是否匹配。請像這樣自由插入一些特殊的狀況來探測匹配的次序。
    /articles/2003 不匹配任何一個模式,由於每一個模式要求URL 以一個反斜線結尾。
    /articles/2003/03/03/ 將匹配最後一個模式。Django 將調用函數views.article_detail(request, '2003', '03', '03')。
    
        '''

    APPEND_SLASH

    # 是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑的配置項
    APPEND_SLASH=True

    Django settings.py配置文件中默認沒有 APPEND_SLASH 這個參數,但 Django 默認這個參數爲 APPEND_SLASH = True。 其做用就是自動在網址結尾加'/'。

    其效果就是:

    咱們定義了urls.py:

    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
            url(r'^blog/$', views.blog),
    ]
    
    訪問 http://www.example.com/blog 時,默認將網址自動轉換爲 http://www.example/com/blog/ 。
    
    若是在settings.py中設置了 APPEND_SLASH=False,此時咱們再請求 http://www.example.com/blog 時就會提示找不到頁面。

三.有名分組和無名分組:

urlpatterns = [
    url(r'^homepage/(\d+)/(\d+)$', views.homepage),#無名多分組
    #在Python 正則表達式中,命名正則表達式組的語法是(?P<name>pattern),其中name 是組的名稱,pattern 是要匹配的模式。
    url(r'^publish_modfiy/(?P<id>\d+)/$',publish.publish_modfiy,),#有名分組
分組的做用:有名分組與無名分組通常用在前端傳數據到後端的時候將標識某個數據的屬性傳遞給後端。
# def publish_modfiy(request,*args):接受多個無名分組時
#def publish_modfiy(request,id):在視圖層中必須接收前端傳的值,接受有名分組傳來的值

四 路由分發

#主urls
from django.urls import path,re_path,include
from app01 import views

from app01 import urls
urlpatterns = [ 
  re_path(r'^app01/',include('app01.urls')),#行  對應1.1版本中的urls
  # re_path(r'^app01/&',include('app01.urls')),#不行
  path('app01/',include('app01.urls')),#行 path是在Django2.0中才有的
  #path('app01/', include(urls)),
]

在app01裏建立一個urls

from django.urls import path,re_path
from app01 import views
urlpatterns = [
    re_path(r'^test/(?P<year>[0-9]{2})/$',views.url_test),
]

五 反向解析

在使用Django 項目時,一個常見的需求是得到URL 的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。人們強烈但願不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 絕不相關的專門的URL 生成機制,由於這樣容易致使必定程度上產生過時的URL。

在須要URL 的地方,對於不一樣層級,Django 提供不一樣的工具用於URL 反查:

  • 在模板中:使用url 模板標籤。
  • 在Python 代碼中:使用from django.urls import reverse()函數
  • 簡單的說反向解析的做用就當url從新命名時候,視圖函數,前端調用該路由次數過多須要一次次的去進行修改,用了反向解析後不用修改,可以動態捕捉到之前對應的url.
  • 在視圖層本質上是去除地址,重定向來用,在模板層:取出地址,是爲了發請求來用

urls.py

from django.urls import path,re_path
from app01 import views
urlpatterns = [
    re_path(r'^test/(?P<year>[0-9]{2})/(?P<month>[0-9]{2})/$',views.url_test,name='test'),
]

html文件

<a href="{% url 'test' 10 23 %}">哈哈</a>

視圖函數中:

from django.shortcuts import render, HttpResponse,redirect,reverse
def url_test(request,year,month):
    print(year)
    print(month)
    url=reverse('test',args=(10,20))
    print(url)
    return HttpResponse('ok')

總結:1 在html代碼裏{% url "別名" 參數 參數%}

   2 在視圖函數中:

    2.1 url=reverse('test')

    2.2 url=reverse('test',args=(10,20))

當命名你的URL 模式時,請確保使用的名稱不會與其它應用中名稱衝突。若是你的URL 模式叫作comment,而另一個應用中也有一個一樣的名稱,當你在模板中使用這個名稱的時候不能保證將插入哪一個URL。在URL 名稱中加上一個前綴,好比應用的名稱,將減小衝突的可能。咱們建議使用myapp-comment 而不是comment

url(r'^publish_modfiy/(?P<id>\d+)/$', publish.publish_modfiy, name='app01_publish_modfiy'),
    url(r'^publish_modfiy/(?P<id>\d+)/$', publish.publish_modfiy, name='app02_publish_modfiy'),
  #前綴加APP的名稱

六 名稱空間

命名空間(英語:Namespace)是表示標識符的可見範圍。一個標識符可在多個命名空間中定義,它在不一樣命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何標識符,它們不會與任何已有的標識符發生衝突,由於已有的定義都處於其它命名空間中。

因爲name沒有做用域,Django在反解URL時,會在項目全局順序搜索,當查找到第一個name指定URL時,當即返回

咱們在開發項目時,會常用name屬性反解出URL,當不當心在不一樣的app的urls中定義相同的name時,可能會致使URL反解錯誤,爲了不這種事情發生,引入了命名空間。

名稱空間是在反向解析命名相同名稱的時候纔會派上用場,因此儘可能命名成不一樣的名稱。

urls.py

from django.urls import path,re_path,include
urlpatterns = [
    path('app01/', include('app01.urls')),
    path('app02/', include('app02.urls'))
]

app01 的urls.py

from django.urls import path,re_path
from app01 import views
urlpatterns = [
    re_path(r'index/',views.index,name='index'),
]

app02 的urls.py

from django.urls import path, re_path, include
from app02 import views

urlpatterns = [
    re_path(r'index/', views.index,name='index'),

]

app01的視圖函數

def index(request):
    url=reverse('index')
    print(url)
    return HttpResponse('index app01')

app02的視圖函數

def index(request):
    url=reverse('index')
    print(url)
    return HttpResponse('index app02')

這樣都找index,app01和app02找到的都是app02的index

如何處理?在路由分發的時候指定名稱空間

總urls.py在路由分發時,指定名稱空間

path('app01/', include(('app01.urls','app01'))),
 path('app02/', include(('app02.urls','app02')))
 url(r'app01/',include('app01.urls',namespace='app01')),
 url(r'app02/',include('app02.urls',namespace='app02'))
 url(r'app01/',include(('app01.urls','app01'))),
 url(r'app02/',include(('app02.urls','app02')))

視圖函數反向解析的時候,指定是那個名稱空間下的

url=reverse('app02:index')
 print(url)
 url2=reverse('app01:index')
 print(url2)

在模版裏:

<a href="{% url 'app02:index'%}">哈哈</a>

七.僞靜態網頁

僞靜態網頁是將路由假裝成一個靜態的網頁,爲了繞過百度搜索動態網頁。

urlpatterns = [
    url(r'index/.html', views.index,name='index'),
    #加入html後綴就假裝成了靜態網頁

八.文件上傳

文件上傳須要注意的事項:

(1).method須要制定完成post

(2).enctype:須要設置成formdata格式,request從前端獲取的數據是放在request.FILES中的

而不是在POST文件中,

file_obj = request.FILES.get('my_file)
print(file_obj.name)
with open(file_obj,mode='wb) as f:
    for line in f.read():
        f.write(line)

九.Django2.0和1.0版本之間的區別

django2.0版的path

jango2.0的re_path和1.0的url同樣

思考狀況以下:

urlpatterns = [  
    re_path('articles/(?P<year>[0-9]{4})/', year_archive),  
    re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),  
]

考慮下這樣的兩個問題:

第一個問題,函數 year_archive 中year參數是字符串類型的,所以須要先轉化爲整數類型的變量值,固然year=int(year) 不會有諸如如TypeError或者ValueError的異常。那麼有沒有一種方法,在url中,使得這一轉化步驟能夠由Django自動完成?

第二個問題,三個路由中article_id都是一樣的正則表達式,可是你須要寫三遍,當以後article_id規則改變後,須要同時修改三處代碼,那麼有沒有一種方法,只需修改一處便可?

在Django2.0中,可使用 path 解決以上的兩個問題。

from django.urls import path  
from . import views  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<int:year>/', views.year_archive),  
    path('articles/<int:year>/<int:month>/', views.month_archive),  
    path('articles/<int:year>/<int:month>/<slug>/', views.article_detail),  

  # path才支持,re_path不支持
  path('order/<int:year>',views.order),
] #order只能在2.0中使用

基本規則:

  • 使用尖括號(<>)從url中捕獲值。
  • 捕獲值中能夠包含一個轉化器類型(converter type),好比使用 <int:name> 捕獲一個整數變量。若果沒有轉化器,將匹配任何字符串,固然也包括了 / 字符。
  • 無需添加前導斜槓。

如下是根據 2.0官方文檔 而整理的示例分析表:(跟上面url的匹配關係)

path轉化器

Django默認支持如下5個轉化器:

--str,匹配除了路徑分隔符(/)以外的非空字符串,這是默認的形式
--int,匹配正整數,包含0。
--slug,匹配字母、數字以及橫槓、下劃線組成的字符串。
--uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
--path,匹配任何非空字符串,包含了路徑分隔符(/)(不能用?)

註冊自定義轉化器

對於一些複雜或者複用的須要,能夠定義本身的轉化器。轉化器是一個類或接口,它的要求有三點:

  • regex 類屬性,字符串類型
  • to_python(self, value) 方法,value是由類屬性 regex 所匹配到的字符串,返回具體的Python變量值,以供Django傳遞到對應的視圖函數中。
  • to_url(self, value) 方法,和 to_python 相反,value是一個具體的Python變量值,返回其字符串,一般用於url反向引用
class FourDigitYearConverter:  
    regex = '[0-9]{4}'  #正則表達式
    def to_python(self, value):  #對python變量而言,匹配到的字符串返回Int
        return int(value)  
    def to_url(self, value):  
        return '%04d' % value  #對路由url而言,返回自動補全後的字符串
django.urls import register_converter, path  
from . import converters, views
#使用register_converter 將其註冊到URL配置中:
register_converter(converters.FourDigitYearConverter, 'yyyy')  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<yyyy:year>/', views.year_archive),  
    ...  
]

視圖層

一.視圖函數:

視圖函數簡稱視圖,是一個簡單的Python 函數,它接受Web請求而且返回Web響應。響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片. . . 是任何東西均可以。不管視圖自己包含什麼邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你的Python目錄下面。除此以外沒有更多的要求了——能夠說「沒有什麼神奇的地方」。爲了將代碼放在某處,約定是將視圖放置在項目或應用程序目錄中的名爲views.py的文件中。

下面是一個返回當前日期和時間做爲HTML文檔的視圖:

from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

讓咱們逐行閱讀上面的代碼:

  • 首先,咱們從 django.shortcuts模塊導入了HttpResponse類,以及Python的datetime庫。

  • 接着,咱們定義了current_datetime函數。它就是視圖函數。每一個視圖函數都使用HttpRequest對象做爲第一個參數,而且一般稱之爲request

    注意,視圖函數的名稱並不重要;不須要用一個統一的命名方式來命名,以便讓Django識別它。咱們將其命名爲current_datetime,是由於這個名稱可以精確地反映出它的功能。

  • 這個視圖會返回一個HttpResponse對象,其中包含生成的響應。每一個視圖函數都負責返回一個HttpResponse對象。

視圖層,熟練掌握兩個對象便可:請求對象(request)和響應對象(HttpResponse)

二.HttpRequest對象

request屬性:django將請求報文中的請求行、首部信息、內容主體封裝成 HttpRequest 類中的屬性。 除了特殊說明的以外,其餘均爲只讀的

'''

1.HttpRequest.GET

  一個相似於字典的對象,包含 HTTP GET 的全部參數。詳情請參考 QueryDict 對象。

2.HttpRequest.POST

  一個相似於字典的對象,若是請求中包含表單數據,則將這些數據封裝成 QueryDict 對象。

  POST 請求能夠帶有空的 POST 字典 —— 若是經過 HTTP POST 方法發送一個表單,可是表單中沒有任何的數據,QueryDict 對象依然會被建立。
   所以,不該該使用 if request.POST  來檢查使用的是不是POST 方法;應該使用 if request.method == "POST"
  另外:若是使用 POST 上傳文件的話,文件信息將包含在 FILES 屬性中。
   
   注意:鍵值對的值是多個的時候,好比checkbox類型的input標籤,select標籤,須要用:
        request.POST.getlist("hobby")

3.HttpRequest.body

  一個字符串,表明請求報文的主體。在處理非 HTTP 形式的報文時很是有用,例如:二進制圖片、XML,Json等。
  可是,若是要處理表單數據的時候,推薦仍是使用 HttpRequest.POST 。


4.HttpRequest.path

  一個字符串,表示請求的路徑組件(不含域名)。
  例如:"/music/bands/the_beatles/"

5.HttpRequest.method

  一個字符串,表示請求使用的HTTP 方法。必須使用大寫。
  例如:"GET"、"POST"


6.HttpRequest.encoding

  一個字符串,表示提交的數據的編碼方式(若是爲 None 則表示使用 DEFAULT_CHARSET 的設置,默認爲 'utf-8')。
   這個屬性是可寫的,你能夠修改它來修改訪問表單數據使用的編碼。
   接下來對屬性的任何訪問(例如從 GET 或 POST 中讀取數據)將使用新的 encoding 值。
   若是你知道表單數據的編碼不是 DEFAULT_CHARSET ,則使用它。


7.HttpRequest.META

   一個標準的Python 字典,包含全部的HTTP 首部。具體的頭部信息取決於客戶端和服務器,下面是一些示例:
  取值:

    CONTENT_LENGTH —— 請求的正文的長度(是一個字符串)。
    CONTENT_TYPE —— 請求的正文的MIME 類型。
    HTTP_ACCEPT —— 響應可接收的Content-Type。
    HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。
    HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。
    HTTP_HOST —— 客服端發送的HTTP Host 頭部。
    HTTP_REFERER —— Referring 頁面。
    HTTP_USER_AGENT —— 客戶端的user-agent 字符串。
    QUERY_STRING —— 單個字符串形式的查詢字符串(未解析過的形式)。
    REMOTE_ADDR —— 客戶端的IP 地址。
    REMOTE_HOST —— 客戶端的主機名。
    REMOTE_USER —— 服務器認證後的用戶。
    REQUEST_METHOD —— 一個字符串,例如"GET" 或"POST"。
    SERVER_NAME —— 服務器的主機名。
    SERVER_PORT —— 服務器的端口(是一個字符串)。
   從上面能夠看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 以外,請求中的任何 HTTP 首部轉換爲 META 的鍵時,
    都會將全部字母大寫並將鏈接符替換爲下劃線最後加上 HTTP_  前綴。
    因此,一個叫作 X-Bender 的頭部將轉換成 META 中的 HTTP_X_BENDER 鍵。

8.HttpRequest.FILES

  一個相似於字典的對象,包含全部的上傳文件信息。
   FILES 中的每一個鍵爲<input type="file" name="" /> 中的name,值則爲對應的數據。
  注意,FILES 只有在請求的方法爲POST 且提交的<form> 帶有enctype="multipart/form-data" 的狀況下才會
   包含數據。不然,FILES 將爲一個空的相似於字典的對象。


9.HttpRequest.COOKIES

  一個標準的Python 字典,包含全部的cookie。鍵和值都爲字符串。



10.HttpRequest.session

   一個既可讀又可寫的相似於字典的對象,表示當前的會話。只有當Django 啓用會話的支持時纔可用。
    完整的細節參見會話的文檔。


11.HttpRequest.user(用戶認證組件下使用)

  一個 AUTH_USER_MODEL 類型的對象,表示當前登陸的用戶。

  若是用戶當前沒有登陸,user 將設置爲 django.contrib.auth.models.AnonymousUser 的一個實例。你能夠經過 is_authenticated() 區分它們。

    例如:

    if request.user.is_authenticated():
        # Do something for logged-in users.
    else:
        # Do something for anonymous users.


       user 只有當Django 啓用 AuthenticationMiddleware 中間件時纔可用。

     -------------------------------------------------------------------------------------

    匿名用戶
    class models.AnonymousUser

    django.contrib.auth.models.AnonymousUser 類實現了django.contrib.auth.models.User 接口,但具備下面幾個不一樣點:

    id 永遠爲None。
    username 永遠爲空字符串。
    get_username() 永遠返回空字符串。
    is_staff 和 is_superuser 永遠爲False。
    is_active 永遠爲 False。
    groups 和 user_permissions 永遠爲空。
    is_anonymous() 返回True 而不是False。
    is_authenticated() 返回False 而不是True。
    set_password()、check_password()、save() 和delete() 引起 NotImplementedError。
    New in Django 1.8:
    新增 AnonymousUser.get_username() 以更好地模擬 django.contrib.auth.models.User。

*/

request經常使用方法:

'''
1.HttpRequest.get_full_path()

  返回 path,若是能夠將加上查詢字符串。

  例如:"/music/bands/the_beatles/?print=true"
  注意和path的區別:http://127.0.0.1:8001/order/?name=lqz&age=10

2.HttpRequest.is_ajax()

  若是請求是經過XMLHttpRequest 發起的,則返回True,方法是檢查 HTTP_X_REQUESTED_WITH 相應的首部是不是字符串'XMLHttpRequest'。

  大部分現代的 JavaScript 庫都會發送這個頭部。若是你編寫本身的 XMLHttpRequest 調用(在瀏覽器端),你必須手工設置這個值來讓 is_ajax() 能夠工做。

  若是一個響應須要根據請求是不是經過AJAX 發起的,而且你正在使用某種形式的緩存例如Django 的 cache middleware,
   你應該使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 裝飾你的視圖以讓響應可以正確地緩存。

'''

三.HttpResponse對象

響應對象主要有三種形式:

  • HttpResponse()
  • render()
  • redirect()

HttpResponse()括號內直接跟一個具體的字符串做爲響應體,比較直接很簡單,因此這裏主要介紹後面兩種形式。

render():
參數:
     request: 用於生成響應的請求對象。

     template_name:要使用的模板的完整名稱,可選的參數

     context:添加到模板上下文的一個字典。默認是一個空字典。若是字典中的某個值是可調用的,視圖將在渲染模板以前調用它。

     content_type:生成的文檔要使用的MIME類型。默認爲 DEFAULT_CONTENT_TYPE 設置的值。默認爲'text/html'

     status:響應的狀態碼。默認爲200。

   useing: 用於加載模板的模板引擎的名稱。


from django.shortcuts import render

def my_view(request):
    # 視圖的代碼寫在這裏
    return render(request, 'myapp/index.html', {'foo': 'bar'}) 
    
上面的代碼等於    

from django.http import HttpResponse
from django.template import loader

def my_view(request):
    # 視圖代碼寫在這裏
    t = loader.get_template('myapp/index.html')
    c = {'foo': 'bar'}
    return HttpResponse(t.render(c, request))
redirect():

參數能夠是:

  • 一個模型:將調用模型的get_absolute_url() 函數
  • 一個視圖,能夠帶有參數:將使用urlresolvers.reverse 來反向解析名稱
  • 一個絕對的或相對的URL,將原封不動的做爲重定向的位置。

默認返回一個臨時的重定向;傳遞permanent=True 能夠返回一個永久的重定向。

def my_view(request):
    ...
    return redirect('/some/url/')
也能夠是一個完整的URL:

def my_view(request):
    ...
    return redirect('http://www.baidu.com/') 
'------------------------------------------------------------------'
默認狀況下,redirect() 返回一個臨時重定向。以上全部的形式都接收一個permanent 參數;若是設置爲True,將返回一個永久的重定向:

def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object, permanent=True)  
臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通用戶來講是沒什麼區別的,它主要面向的是搜索引擎的機器人。

A頁面臨時重定向到B頁面,那搜索引擎收錄的就是A頁面。

A頁面永久重定向到B頁面,那搜索引擎收錄的就是B頁面。

""" 
1)301和302的區別。

  301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址能夠從響應的Location首部中獲取
  (用戶看到的效果就是他輸入的地址A瞬間變成了另外一個地址B)——這是它們的共同點。

  他們的不一樣在於。301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時也將舊的網址交換爲重定向以後的網址;

  302表示舊地址A的資源還在(仍然能夠訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜索引擎會抓取新的內容而保存舊的網址。 SEO302好於301

2)重定向緣由:
(1)網站調整(如改變網頁目錄結構);
(2)網頁被移到一個新地址;
(3)網頁擴展名改變(如應用須要把.php改爲.Html或.shtml)。
        這種狀況下,若是不作重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶獲得一個404頁面錯誤信息,訪問流量白白喪失;再者某些註冊了多個域名的
    網站,也須要經過重定向讓訪問這些域名的用戶自動跳轉到主站點等。

重定向301和302的區別
"""

四.JsonResponse

# 第一種方式
    # import json
    # data={'name':'lqz','age':18}
    # data1=['lqz','egon']
    # return HttpResponse(json.dumps(data1))
    # 第二種方式
    from django.http import JsonResponse
    # data = {'name': 'lqz', 'age': 18}
    data1 = ['lqz', 'egon']
    # return JsonResponse(data)
    return JsonResponse(data1,safe=False) #safe改成False是爲了將不是dict格式的數據jason序列化
    return JsonResponse(data1,json_dumps_params={'ensure_ascii':False})  #將ensure_ascii設置爲False是爲了解決中文顯示問題

兩種方式

五.CBV和FBV

CBV基於類的視圖(Class base view)和FBV基於函數的視圖(Function base view)

#在視圖層
from django.views import View
class AddPublish(View): #每個功能都去定義一個類
    def dispatch(self, request, *args, **kwargs):
        print(request)
        print(args)
        print(kwargs)
        # 能夠寫相似裝飾器的東西,在先後加代碼
        obj=super().dispatch(request, *args, **kwargs)
        return obj
    def get(self,request):
        return render(request,'index.html')
    def post(self,request):
        request
        return HttpResponse('post')
    
    
#在路由層
# urls.py中
url(r'^add_class/$', views.AddPublish.as_view()),
使用裝飾器裝飾FBV

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

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

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

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中提供了method_decorator裝飾器用於將函數裝飾器轉換爲方法裝飾器。

# CBV版添加班級
from django.views import View
from django.utils.decorators import method_decorator

class AddClass(View):

    @method_decorator(wrapper)
    def get(self, request):
        return render(request, "add_class.html")

    def post(self, request):
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")
CBV的擴展閱讀
# 使用CBV時要注意,請求過來後會先執行dispatch()這個方法,若是須要批量對具體的請求處理方法,如get,post等作一些操做的時候,這裏咱們能夠手動改寫dispatch方法,這個dispatch方法就和在FBV上加裝飾器的效果同樣。

class Login(View):
     
    def dispatch(self, request, *args, **kwargs):
        print('before')
        obj = super(Login,self).dispatch(request, *args, **kwargs)
        print('after')
        return obj
 
    def get(self,request):
        return render(request,'login.html')
 
    def post(self,request):
        print(request.POST.get('user'))
        return HttpResponse('Login.post')

模板層

一.模板層簡介

你可能已經注意到咱們在例子視圖中返回文本的方式有點特別。 也就是說,HTML被直接硬編碼在 Python代碼之中。

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

儘管這種技術便於解釋視圖是如何工做的,但直接將HTML硬編碼到你的視圖裏卻並非一個好主意。 讓咱們來看一下爲何:

  • 對頁面設計進行的任何改變都必須對 Python 代碼進行相應的修改。 站點設計的修改每每比底層 Python 代碼的修改要頻繁得多,所以若是能夠在不進行 Python 代碼修改的狀況下變動設計,那將會方便得多。

  • Python 代碼編寫和 HTML 設計是兩項不一樣的工做,大多數專業的網站開發環境都將他們分配給不一樣的人員(甚至不一樣部門)來完成。 設計者和HTML/CSS的編碼人員不該該被要求去編輯Python的代碼來完成他們的工做。

  • 程序員編寫 Python代碼和設計人員製做模板兩項工做同時進行的效率是最高的,遠勝於讓一我的等待另外一我的完成對某個既包含 Python又包含 HTML 的文件的編輯工做。

基於這些緣由,將頁面的設計和Python的代碼分離開會更乾淨簡潔更容易維護。 咱們可使用 Django的 模板系統 (Template System)來實現這種模式,這就是本章要具體討論的問題

python的模板:HTML代碼+模板語法

def current_time(req):
    # ================================原始的視圖函數
    # import datetime
    # now=datetime.datetime.now()
    # html="<html><body>如今時刻:<h1>%s.</h1></body></html>" %now


    # ================================django模板修改的視圖函數
    # from django.template import Template,Context
    # now=datetime.datetime.now()
    # t=Template('<html><body>如今時刻是:<h1>{{current_date}}</h1></body></html>')
    # #t=get_template('current_datetime.html')
    # c=Context({'current_date':str(now)})
    # html=t.render(c)
    #
    # return HttpResponse(html)


    #另外一種寫法(推薦)
    import datetime
    now=datetime.datetime.now()
    return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})

二 模版語法之變量

模版語法重點:

  變量:{{ 變量名 }}

    1 深度查詢 用句點符

    2 過濾器

  變量相關的用{{}},邏輯相關的用{%%}。

views.py
def template_test(request):
    name = 'lqz'
    li = ['lqz', 1, '18']
    dic = {'name': 'lqz', 'age': 18}
    ll2 = [
        {'name': 'lqz', 'age': 18},
        {'name': 'lqz2', 'age': 19},
        {'name': 'egon', 'age': 20},
        {'name': 'kevin', 'age': 23}
    ]
    ll3=[]
    class Person:
        def __init__(self, name):
            self.name = name

        def test(self):
            print('test函數')
            return 11

        @classmethod
        def test_classmethod(cls):
            print('類方法')
            return '類方法'

        @staticmethod
        def static_method():
            print('靜態方法')
            return '靜態方法'

    lqz = Person('lqz')
    egon = Person('egon')
    person_list = [lqz, egon]
    bo = True
    te = test()
    import datetime
    now=datetime.datetime.now()
    link1='<a href="https://www.baidu.com">點我<a>'
    from django.utils import safestring
    link=safestring.mark_safe(link1)
    # html特殊符號對照表(http://tool.chinaz.com/Tools/htmlchar.aspx)

    # 這樣傳到前臺不會變成特殊字符,由於django給處理了
    dot='&spades;'


    # return render(request, 'template_index.html', {'name':name,'person_list':person_list})
    return render(request, 'template_index.html', locals())
html.py
<p>{{ name }}</p>
            <p>{{ li }}</p>
            <p>{{ dic }}</p>
            <p>{{ lqz }}</p>
            <p>{{ person_list }}</p>
            <p>{{ bo }}</p>
            <p>{{ te }}</p>

            <hr>
            <h3>深度查詢句點符</h3>
            <p>{{ li.1 }}</p>
            <p>{{ dic.name }}</p>
            <p>{{ lqz.test }}</p>
            <p>{{ lqz.name }}</p>
            <p>{{ person_list.0 }}</p>
            <p>{{ person_list.1.name }}</p>

            <hr>
            <h3>過濾器</h3>
            {#注意:冒號後面不能加空格#}
            <p>{{ now | date:"Y-m-d H:i:s" }}</p>

            {#若是變量爲空,設置默認值,空數據,None,變量不存在,都適用#}
            <p>{{ name |default:'數據爲空' }}</p>
            {#計算長度,只有一個參數#}
            <p>{{ person_list |length }}</p>
            {#計算文件大小#}
            <p>{{ 1024 |filesizeformat }}</p>

            {#字符串切片,前閉後開,前面取到,後面取不到#}
            <p>{{ 'hello world lqz' |slice:"2:-1" }}</p>
            <p>{{ 'hello world lqz' |slice:"2:5" }}</p>

            {#截斷字符,至少三個起步,由於會有三個省略號(傳負數,1,2,3都是三個省略號)#}
            <p>{{ '劉清政 world lqz' |truncatechars:"4" }}</p>
            {#截斷文字,以空格作區分,這個不算省略號#}
            <p>{{ '劉清政   是      大帥比 謝謝' |truncatewords:"1" }}</p>

            <p>{{ link1 }}</p>
            <p>{{ link1|safe }}</p>
            <p>{{ link }}</p>

            <p>&spades;</p>
            <p>{{ dot }}</p>

            {#add   能夠加負數,傳數字字符串均可以#}
            <p>{{ "10"|add:"-2" }}</p>
            <p>{{ li.1|add:"-2" }}</p>
            <p>{{ li.1|add:2 }}</p>
            <p>{{ li.1|add:"2" }}</p>
            <p>{{ li.1|add:"-2e" }}</p>

            {#upper#}
            <p>{{ name|upper }}</p>
            <p>{{ 'LQZ'|lower }}</p>
            <hr>
            <h3>模版語法之標籤</h3>
            {#for 循環 循環列表,循環字典,循環列表對象#}
            <ui>
                {% for foo in dic %}
                    {{ foo }}
                {% endfor %}
                {#也能夠混用html標籤#}
                {% for foo in li %}
                    <ul>foo</ul>

                {% endfor %}
            </ui>
            {#表格#}
            <table border="1">

                {% for foo in ll2 %}
                    <tr>
                        <td>{{ foo.name }}</td>
                        <td>{{ foo.age }}</td>
                    </tr>
                {% endfor %}
            </table>
            <table border="1">
                {#'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 4, 'revcounter0': 3, 'first': True, 'last': False}#}
                {% for foo in ll2 %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        <td>{{ foo.name }}</td>
                        <td>{{ foo.age }}</td>
                    </tr>
                {% endfor %}


            </table>



            {% for foo in ll5 %}
                <p>foo.name</p>
            {% empty %}
                <p>空的</p>
            {% endfor %}

            <hr>
            <h3>if判斷</h3>
            {% if name %}
                <a href="">hi {{ name }}</a>
                <a href="">註銷</a>
            {% else %}
                <a href="">請登陸</a>
                <a href="">註冊</a>
            {% endif %}
            {#還有elif#}
            <hr>
            <h3>with</h3>
            {% with ll2.0.name as n %}
                {{ n }}
            {% endwith %}
            {{ n }}


            {% load my_tag_filter %}

            {{ 3|multi_filter:3 }}

            {#傳參必須用空格區分#}
            {% multi_tag 3 9 10 %}

            {#能夠跟if連用#}
            {% if 3|multi_filter:3 > 9 %}
                <p>大於</p>
            {% else %}
                <p>小於</p>
            {% endif %}

意:句點符也能夠用來引用對象的方法(無參數方法):

<h4>字典:{{ dic.name.upper }}<``/``h4>
    #能夠調用數據格式自己的方法

三 模版之過濾器

語法:

{{obj|filter__name:param}}  變量名字|過濾器名稱:變量

default

若是一個變量是false或者爲空,使用給定的默認值。不然,使用變量的值。例如:

`{{ value|default:``"nothing"` `}}`

length

返回值的長度。它對字符串和列表都起做用。例如:

`{{ value|length }}`

若是 value 是 ['a', 'b', 'c', 'd'],那麼輸出是 4。

filesizeformat

將值格式化爲一個 「人類可讀的」 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:

`{{ value|filesizeformat }}`

若是 value 是 123456789,輸出將會是 117.7 MB。  

date

若是 value=datetime.datetime.now()

`{{ value|date:``"Y-m-d"` `}}  `

slice

若是 value="hello world"

`{{ value|``slice``:``"2:-1"` `}}`

truncatechars

若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。

參數:要截斷的字符數

例如:

`{{ value|truncatechars:``9` `}}`

safe

Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的沒必要轉義。好比:

`value``=``"<a href="``">點擊</a>"`

其餘過濾器(拓展)

過濾器 描述 示例
upper 以大寫方式輸出 {{ user.name | upper }}
add 給value加上一個數值 {{ user.age | add:」5」 }}
addslashes 單引號加上轉義號
capfirst 第一個字母大寫 {{ ‘good’| capfirst }} 返回」Good」
center 輸出指定長度的字符串,把變量居中 {{ 「abcd」| center:」50」 }}
cut 刪除指定字符串 {{ 「You are not a Englishman」 | cut:」not」 }}
date 格式化日期
default 若是值不存在,則使用默認值代替 {{ value | default:」(N/A)」 }}
default_if_none 若是值爲None, 則使用默認值代替
dictsort 按某字段排序,變量必須是一個dictionary {% for moment in moments | dictsort:」id」 %}
dictsortreversed 按某字段倒序排序,變量必須是dictionary
divisibleby 判斷是否能夠被數字整除 {{ 224 | divisibleby:2 }} 返回 True
escape 按HTML轉義,好比將」<」轉換爲」&lt」
filesizeformat 增長數字的可讀性,轉換結果爲13KB,89MB,3Bytes等 {{ 1024 | filesizeformat }} 返回 1.0KB
first 返回列表的第1個元素,變量必須是一個列表
floatformat 轉換爲指定精度的小數,默認保留1位小數 {{ 3.1415926 | floatformat:3 }} 返回 3.142 四捨五入
get_digit 從個位數開始截取指定位置的數字 {{ 123456 | get_digit:’1’}}
join 用指定分隔符鏈接列表 {{ [‘abc’,’45’] | join:’’ }} 返回 abc45
length 返回列表中元素的個數或字符串長度
length_is 檢查列表,字符串長度是否符合指定的值 {{ ‘hello’| length_is:’3’ }}
linebreaks


標籤包裹變量

{{ 「Hi\n\nDavid」|linebreaks }} 返回

Hi

David

linebreaksbr
標籤代替換行符
linenumbers 爲變量中的每一行加上行號
ljust 輸出指定長度的字符串,變量左對齊 {{‘ab’|ljust:5}}返回 ‘ab ’
lower 字符串變小寫
make_list 將字符串轉換爲列表
pluralize 根據數字肯定是否輸出英文複數符號
random 返回列表的隨機一項
removetags 刪除字符串中指定的HTML標記 {{value | removetags: 「h1 h2」}}
rjust 輸出指定長度的字符串,變量右對齊
slice 切片操做, 返回列表 {{[3,9,1] | slice:’:2’}} 返回 [3,9] {{ 'asdikfjhihgie' | slice:':5' }} 返回 ‘asdik’
slugify 在字符串中留下減號和下劃線,其它符號刪除,空格用減號替換 {{ '5-2=3and5 2=3' | slugify }} 返回 5-23and5-23
stringformat 字符串格式化,語法同python
time 返回日期的時間部分
timesince 以「到如今爲止過了多長時間」顯示時間變量 結果可能爲 45days, 3 hours
timeuntil 以「從如今開始到時間變量」還有多長時間顯示時間變量
title 每一個單詞首字母大寫
truncatewords 將字符串轉換爲省略表達方式 {{ 'This is a pen' | truncatewords:2 }}返回``This is ...
truncatewords_html 同上,但保留其中的HTML標籤 {{ '<p>This is a pen</p>' | truncatewords:2 }}返回``<p>This is ...</p>
urlencode 將字符串中的特殊字符轉換爲url兼容表達方式 {{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}}
urlize 將變量字符串中的url由純文本變爲連接
wordcount 返回變量字符串中的單詞數
yesno 將布爾變量轉換爲字符串yes, no 或maybe {{ True | yesno }}{{ False | yesno }}{{ None | yesno }} ``返回 ``yes``no ``maybe

四 模版之標籤

標籤看起來像是這樣的: {% tag %}。標籤比變量更加複雜:一些在輸出中建立文本,一些經過循環或邏輯來控制流程,一些加載其後的變量將使用到的額外信息到模版中。一些標籤須要開始和結束標籤 (例如{% tag %} ...標籤 內容 ... {% endtag %})。

for標籤:

遍歷每個元素:

{% for person in person_list %}
    <p>{{ person.name }}</p>
{% endfor %}

能夠利用{% for obj in list reversed %}反向完成循環。

遍歷一個字典:

{% for key,val in dic.items %}
    <p>{{ key }}:{{ val }}</p>
{% endfor %}

注:循環序號能夠經過{{forloop}}顯示  

forloop.counter            The current iteration of the loop (1-indexed) 當前循環的索引值(從1開始)
forloop.counter0           The current iteration of the loop (0-indexed) 當前循環的索引值(從0開始)
forloop.revcounter         The number of iterations from the end of the loop (1-indexed) 當前循環的倒序索引值(從1開始)
forloop.revcounter0        The number of iterations from the end of the loop (0-indexed) 當前循環的倒序索引值(從0開始)
forloop.first              True if this is the first time through the loop 當前循環是否是第一次循環(布爾值)
forloop.last               True if this is the last time through the loop 當前循環是否是最後一次循環(布爾值)
forloop.parentloop         本層循環的外層循環

for...empty:

for 標籤帶有一個可選的{% empty %} 從句,以便在給出的組是空的或者沒有被找到時,能夠有所操做。

{% for person in person_list %}
    <p>{{ person.name }}</p>

{% empty %}
    <p>sorry,no person here</p>
{% endfor %}

if 標籤

{% if %}會對一個變量求值,若是它的值是「True」(存在、不爲空、且不是boolean類型的false值),對應的內容塊會輸出。

{% if num > 100 or num < 0 %}
    <p>無效</p>
{% elif num > 80 and num < 100 %}
    <p>優秀</p>
{% else %}
    <p>湊活吧</p>
{% endif %}
#if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷。

with:

使用一個簡單地名字緩存一個複雜的變量,當你須要使用一個「昂貴的」方法(好比訪問數據庫)不少次的時候是很是有用的

例如:

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}
不要寫成as

csrf_token:

{% csrf_token%}

這個標籤用於跨站請求僞造保護

五.自定義標籤和過濾器

一、在settings中的INSTALLED_APPS配置當前app,否則django沒法找到自定義的simple_tag.

二、在app中建立templatetags模塊(模塊名只能是templatetags)

三、建立任意 .py 文件,如:my_tags.py

from django import template
from django.utils.safestring import mark_safe
 
register = template.Library()   #register的名字是固定的,不可改變
 
 
@register.filter
def filter_multi(v1,v2):
    return  v1 * v2
<br>
@register.simple_tag
def simple_tag_multi(v1,v2):
    return  v1 * v2
<br>
@register.simple_tag
def my_input(id,arg):
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)

四、在使用自定義simple_tag和filter的html文件中導入以前建立的 my_tags.py

{``% load my_tags ``%``} 

五、使用simple_tag和filter(如何調用)

------------------------------.html
{% load xxx %}  
      
# num=12
{{ num|filter_multi:2 }} #24
 
{{ num|filter_multi:"[22,333,4444]" }}
 
{% simple_tag_multi 2 5 %}  參數不限,但不能放在if for語句中
{% simple_tag_multi num 5 %}

注意:filter能夠用在if等語句後,simple_tag不能夠

{% if num|filter_multi:30 > 100 %}
    {{ num|filter_multi:30 }}
{% endif %}

六 模版導入入和繼承

模版導入:

  語法:{% include '模版名稱' %}

  如:{% include 'adv.html' %}

adv.html

<div class="adv">
    <div class="panel panel-default">
        <div class="panel-heading">
            <h3 class="panel-title">Panel title</h3>
        </div>
        <div class="panel-body">
            Panel content
        </div>
    </div>
    <div class="panel panel-danger">
        <div class="panel-heading">
            <h3 class="panel-title">Panel title</h3>
        </div>
        <div class="panel-body">
            Panel content
        </div>
    </div>
    <div class="panel panel-warning">
        <div class="panel-heading">
            <h3 class="panel-title">Panel title</h3>
        </div>
        <div class="panel-body">
            Panel content
        </div>
    </div>
</div>

adv.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    {#    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">#}
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .header {
            height: 50px;
            width: 100%;
            background-color: #369;
        }
    </style>
</head>
<body>
<div class="header"></div>

<div class="container">
    <div class="row">
        <div class="col-md-3">
            {% include 'adv.html' %}


        </div>
        <div class="col-md-9">
            {% block conn %}
                <h1>你好</h1>
            {% endblock %}

        </div>
    </div>

</div>

</body>
</html>

base.html
{% extends 'base.html' %}

{% block conn %}
    {{ block.super }}
是啊

{% endblock conn%}

order.html

模板的繼承:

Django模版引擎中最強大也是最複雜的部分就是模版繼承了。模版繼承可讓您建立一個基本的「骨架」模版,它包含您站點中的所有元素,而且能夠定義可以被子模版覆蓋的 blocks 。

經過從下面這個例子開始,能夠容易的理解模版繼承:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css"/>
    <title>{% block title %}My amazing site{% endblock %}</title>
</head>

<body>
<div id="sidebar">
    {% block sidebar %}
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
    {% endblock %}
</div>

<div id="content">
    {% block content %}{% endblock %}
</div>
</body>
</html>

這個模版,咱們把它叫做 base.html, 它定義了一個能夠用於兩列排版頁面的簡單HTML骨架。「子模版」的工做是用它們的內容填充空的blocks。

在這個例子中, block 標籤訂義了三個能夠被子模版內容填充的block。 block 告訴模版引擎: 子模版可能會覆蓋掉模版中的這些位置。

子模版可能看起來是這樣的:

{% extends "base.html" %}
 
{% block title %}My amazing blog{% endblock %}
 
{% block content %}
{% for entry in blog_entries %}
    <h2>{{ entry.title }}</h2>
    <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

extends 標籤是這裏的關鍵。它告訴模版引擎,這個模版「繼承」了另外一個模版。當模版系統處理這個模版時,首先,它將定位父模版——在此例中,就是「base.html」。

那時,模版引擎將注意到 base.html 中的三個 block 標籤,並用子模版中的內容來替換這些block。根據 blog_entries 的值,輸出可能看起來是這樣的:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>My amazing blog</title>
</head>
 
<body>
    <div id="sidebar">
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
    </div>
 
    <div id="content">
        <h2>Entry one</h2>
        <p>This is my first entry.</p>
 
        <h2>Entry two</h2>
        <p>This is my second entry.</p>
    </div>
</body>
</html>

請注意,子模版並無定義 sidebar block,因此係統使用了父模版中的值。父模版的 {% block %} 標籤中的內容老是被用做備選內容(fallback)。

這種方式使代碼獲得最大程度的複用,而且使得添加內容到共享的內容區域更加簡單,例如,部分範圍內的導航。

這裏是使用繼承的一些提示

  • 若是你在模版中使用 {% extends %} 標籤,它必須是模版中的第一個標籤。其餘的任何狀況下,模版繼承都將沒法工做。
  • 在base模版中設置越多的 {% block %} 標籤越好。請記住,子模版沒必要定義所有父模版中的blocks,因此,你能夠在大多數blocks中填充合理的默認內容,而後,只定義你須要的那一個。多一點鉤子總比少一點好。
  • 若是你發現你本身在大量的模版中複製內容,那可能意味着你應該把內容移動到父模版中的一個 {% block %} 中。
  • If you need to get the content of the block from the parent template, the {{ block.super }} variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using {{ block.super }} will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.
  • 爲了更好的可讀性,你也能夠給你的 {% endblock %} 標籤一個 名字 。例如:
{% block content %}
...
{% endblock content %}  

在大型模版中,這個方法幫你清楚的看到哪個  {% block %} 標籤被關閉了。

  • 不能在一個模版中定義多個相同名字的 block 標籤。

能夠將經常使用的頁面內容如導航條,頁尾信息等組件保存在單獨的文件中,而後在須要使用的地方按以下語法導入便可。

{% include 'navbar.html' %}

七 靜態文件相關

{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />

引用JS文件時使用:

{% load static %}
<script src="{% static "mytest.js" %}"></script>

某個文件多處被用到能夠存爲一個變量

{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>

使用get_static_prefix

{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />

或者

{% load static %}
{% get_static_prefix as STATIC_PREFIX %}

<img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />
inclusion_tag

多用於返回html代碼片斷

示例:

templatetags/my_inclusion.py

from django import template

register = template.Library()


@register.inclusion_tag('result.html')
def show_results(n):
    n = 1 if n < 1 else int(n)
    data = ["第{}項".format(i) for i in range(1, n+1)]
    return {"data": data}

templates/snippets/result.html

<ul>
  {% for choice in data %}
    <li>{{ choice }}</li>
  {% endfor %}
</ul>

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>inclusion_tag test</title>
</head>
<body>

{% load inclusion_tag_test %}

{% show_results 10 %}
</body>
</html>
相關文章
相關標籤/搜索