天天看點

Django基礎教程

執行個體練習1-送出資料并展示

1.app_01下的views.py

info_list=[]

def userInfor(req):

    if req.method=="POST":
        username=req.POST.get("username",None)
                             #這裡username是表單name屬性,None是擷取不到時候預設值
        sex=req.POST.get("sex",None)
        email=req.POST.get("email",None)

        info={"username":username,"sex":sex,"email":email}
        info_list.append(info)

    return render(req,"userInfor.html",{"info_list":info_list})                              

2.應用目錄mysite下的urls.py

url(r'^userInfor/', views.userInfor)      

3.templates下的userInfor.html

Django基礎教程
Django基礎教程
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>建立個人資訊</h1>

<form action="/userInfor/" method="post">

    <p>姓名<input type="text" name="username"></p>
    <p>性别<input type="text" name="sex"></p>
    <p>郵箱<input type="text" name="email"></p>
    <p><input type="submit" value="submit"></p>

</form>

<hr>

<h1>資訊展示</h1>

<table border="1">

    <tr>
        <td>姓名</td>
        <td>性别</td>
        <td>郵箱</td>
    </tr>
    {% for i in info_list %}

        <tr>
            <td>{{ i.username }}</td>
            <td>{{ i.sex }}</td>
            <td>{{ i.email }}</td>
        </tr>

    {% endfor %}

</table>

</body>
</html>      

代碼在此

 執行個體練習2-送出資料并展示(資料庫)

1.views.py

Django基礎教程
Django基礎教程
from django.shortcuts import render

from app01 import models
# Create your views here.


def userInfor(req):

    if req.method=="POST":
        u=req.POST.get("username",None)
        s=req.POST.get("sex",None)
        e=req.POST.get("email",None)


       #---------表中插入資料方式一
            # info={"username":u,"sex":e,"email":e}
            # models.UserInfor.objects.create(**info)

       #---------表中插入資料方式二
        models.UserInfor.objects.create(
            username=u,
            sex=s,
            email=e
        )

        info_list=models.UserInfor.objects.all()

        return render(req,"userInfor.html",{"info_list":info_list})

    return render(req,"userInfor.html")      

View Code

2.models.py

Django基礎教程
Django基礎教程
from django.db import models

# Create your models here.


class UserInfor(models.Model):

    username=models.CharField(max_length=64)
    sex=models.CharField(max_length=64)
    email=models.CharField(max_length=64)      

3.userInfor.html

Django基礎教程
Django基礎教程
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>建立個人資訊</h1>

<form action="/userInfor/" method="post">

    <p>姓名<input type="text" name="username"></p>
    <p>性别<input type="text" name="sex"></p>
    <p>郵箱<input type="text" name="email"></p>
    <p><input type="submit" value="submit"></p>

</form>

<hr>

<h1>資訊展示</h1>

<table border="1">

    <tr>
        <td>姓名</td>
        <td>性别</td>
        <td>郵箱</td>
    </tr>
    {% for i in info_list %}

        <tr>
            <td>{{ i.username }}</td>
            <td>{{ i.sex }}</td>
            <td>{{ i.email }}</td>
        </tr>

    {% endfor %}

</table>

</body>
</html>      

四 Django的配置檔案(settings)

靜态檔案設定:

Django基礎教程
Django基礎教程
一、概述:

     #靜态檔案交由Web伺服器處理,Django本身不處理靜态檔案。簡單的處理邏輯如下(以nginx為例):

     #          URI請求-----> 按照Web伺服器裡面的配置規則先處理,以nginx為例,主要求配置在nginx.
                             #conf裡的location

                         |---------->如果是靜态檔案,則由nginx直接處理

                         |---------->如果不是則交由Django處理,Django根據urls.py裡面的規則進行比對

    # 以上是部署到Web伺服器後的處理方式,為了便于開發,Django提供了在開發環境的對靜态檔案的處理機制,方法是這樣:

    #1、在INSTALLED_APPS裡面加入'django.contrib.staticfiles',

    #2、在urls.py裡面加入
       if settings.DEBUG:  
           urlpatterns += patterns('', url(r'^media/(?P<path>.*)$', 
           'django.views.static.serve', {'document_root': settings.MEDIA_ROOT }),   
            url(r'^static/(?P<path>.*)$',
          'django.views.static.serve',{'document_root':settings.STATIC_ROOT}), )  

    # 3、這樣就可以在開發階段直接使用靜态檔案了。

二、MEDIA_ROOT和MEDIA_URL

        #而靜态檔案的處理又包括STATIC和MEDIA兩類,這往往容易混淆,在Django裡面是這樣定義的:

        #MEDIA:指使用者上傳的檔案,比如在Model裡面的FileFIeld,ImageField上傳的檔案。如果你定義

        #MEDIA_ROOT=c:\temp\media,那麼File=models.FileField(upload_to="abc/")#,上傳的檔案就會被儲存到c:\temp\media\abc  
        #eg:
            class blog(models.Model):  
                   Title=models.charField(max_length=64)  
                   Photo=models.ImageField(upload_to="photo") 
        #     上傳的圖檔就上傳到c:\temp\media\photo,而在模闆中要顯示該檔案,則在這樣寫
        #在settings裡面設定的MEDIA_ROOT必須是本地路徑的絕對路徑,一般是這樣寫:
                 BASE_DIR= os.path.abspath(os.path.dirname(__file__))  
                 MEDIA_ROOT=os.path.join(BASE_DIR,'media/').replace('\\','/') 

        #MEDIA_URL是指從浏覽器通路時的位址字首,舉個例子:
            MEDIA_ROOT=c:\temp\media\photo  
            MEDIA_URL="/data/"
        #在開發階段,media的處理由django處理:

        #    通路http://localhost/data/abc/a.png就是通路c:\temp\media\photo\abc\a.png

        #    在模闆裡面這樣寫<img src="{{MEDIA_URL}}abc/a.png">

        #    在部署階段最大的不同在于你必須讓web伺服器來處理media檔案,是以你必須在web伺服器中配置,
        #  以便能讓web伺服器能通路media檔案
        #    以nginx為例,可以在nginx.conf裡面這樣:

                 location ~/media/{
                       root/temp/
                       break;
                    }

        #    具體可以參考如何在nginx部署django的資料。

三、STATIC_ROOT和STATIC_URL、
    STATIC主要指的是如css,js,images這樣檔案,在settings裡面可以配置STATIC_ROOT和STATIC_URL,
    配置方式與MEDIA_ROOT是一樣的,但是要注意

    #STATIC檔案一般儲存在以下位置:

    #1、STATIC_ROOT:在settings裡面設定,一般用來放一些公共的js,css,images等。

    #2、app的static檔案夾,在每個app所在文夾均可以建立一個static檔案夾,然後當運作collectstatic時,
    #    Django會周遊INSTALL_APPS裡面所有app的static檔案夾,将裡面所有的檔案複制到STATIC_ROOT。是以,
    #   如果你要建立可複用的app,那麼你要将該app所需要的靜态檔案放在static檔案夾中。

    # 也就是說一個項目引用了很多app,那麼這個項目所需要的css,images等靜态檔案是分散在各個app的static檔案的,比
    #  較典型的是admin應用。當你要釋出時,需要将這些分散的static檔案收集到一個地方就是STATIC_ROOT。

    #3、STATIC檔案還可以配置STATICFILES_DIRS,指定額外的靜态檔案存儲位置。
    #  STATIC_URL的含義與MEDIA_URL類似。

    # ----------------------------------------------------------------------------
    #注意1:
        #為了後端的更改不會影響前端的引入,避免造成前端大量修改

        STATIC_URL = '/static/'               #引用名
        STATICFILES_DIRS = (
            os.path.join(BASE_DIR,"statics")  #實際名 ,即實際檔案夾的名字
        )

        #django對引用名和實際名進行映射,引用時,隻能按照引用名來,不能按實際名去找
        #<script src="/statics/jquery-3.1.1.js"></script>
        #------error-----不能直接用,必須用STATIC_URL = '/static/':
        #<script src="/static/jquery-3.1.1.js"></script>

    #注意2(statics檔案夾寫在不同的app下,靜态檔案的調用):

        STATIC_URL = '/static/'

        STATICFILES_DIRS=(
            ('hello',os.path.join(BASE_DIR,"app01","statics")) ,
        )

        #<script src="/static/hello/jquery-1.8.2.min.js"></script>

    #注意3:
        STATIC_URL = '/static/'
        {% load staticfiles %}
       # <script src={% static "jquery-1.8.2.min.js" %}></script>      

靜态檔案設定

static配置

#3、STATIC檔案還可以配置STATICFILES_DIRS,指定額外的靜态檔案存儲位置。
    #  STATIC_URL的含義與MEDIA_URL類似。

    # ----------------------------------------------------------------------------
    #注意1:
        #為了後端的更改不會影響前端的引入,避免造成前端大量修改

        STATIC_URL = '/static/'               #引用名
        STATICFILES_DIRS = (
            os.path.join(BASE_DIR,"statics")  #實際名 ,即實際檔案夾的名字
        )

        #django對引用名和實際名進行映射,引用時,隻能按照引用名來,不能按實際名去找
        #<script src="/statics/jquery-3.1.1.js"></script>
        #------error-----不能直接用,必須用STATIC_URL = '/static/':
        #<script src="/static/jquery-3.1.1.js"></script>

    #注意2(statics檔案夾寫在不同的app下,靜态檔案的調用):

        STATIC_URL = '/static/'

        STATICFILES_DIRS=(
            ('hello',os.path.join(BASE_DIR,"app01","statics")) ,
        )

        #<script src="/static/hello/jquery-1.8.2.min.js"></script>

    #注意3:
        STATIC_URL = '/static/'
        {% load staticfiles %}
       # <script src={% static "jquery-1.8.2.min.js" %}></script>      

二 路由配置系統(URLconf)

URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要為該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對于這個URL調用這段代碼,對于那個URL調用那段代碼。

'''
    
    urlpatterns = [
         url(正規表達式, views視圖函數,參數,别名),
]


參數說明:

    一個正規表達式字元串
    一個可調用對象,通常為一個視圖函數或一個指定視圖函數路徑的字元串
    可選的要傳遞給視圖函數的預設參數(字典形式)
    一個可選的name參數

    '''      

2.1 URLconf的正則字元串參數

1、單一路由對應

url(r'^index$', views.index),  #完全比對      

2、基于正則的路由

url(r'^index/(\d*)',views.index),
url(r'^manage/(?P<name>\w*)/(?P<id>\d*),views.manage),      

3、添加額外的參數

url(r'^manage/(?P<name>\w*)',views.manage,{'id':333}),      

4、為路由映射設定名稱

url(r'^home',views.home,name='h1'),
url(r'^index/(\d*)',views.index,name='h2'),      

2.1.1配置

from django.conf.urls import url
from . import views

urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003), 
  #127.0.0.1/articles/2003/ 這樣通路
url(r'^articles/([0-9]{4})/$', views.year_archive), #[0-9]  等于\d
  #127.0.0.1/articles/6666/這樣通路
 url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
  #127.0.0.1/articles/6666/77/這樣通路
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]      

規則:

'''
    NOTE:
    1 一旦比對成功則不再繼續
    2 若要從URL 中捕獲一個值,隻需要在它周圍放置一對圓括号。
    3 不需要添加一個前導的反斜杠,因為每個URL 都有。例如,應該是^articles 而不是 ^/articles。
    4 每個正規表達式前面的'r' 是可選的但是建議加上。      
一些請求的例子:

    /articles/2005/3/ 不比對任何URL 模式,因為清單中的第三個模式要求月份應該是兩個數字。
    /articles/2003/ 将比對清單中的第一個模式不是第二個,因為模式按順序比對,第一個會首先測試是否比對。
    /articles/2005/03/ 請求将比對清單中的第三個模式。Django 将調用函數
                       views.month_archive(request, '2005', '03')。
    '''

      
#設定項是否開啟URL通路位址後面不為/跳轉至帶有/的路徑
APPEND_SLASH=True      

2.1.2 有名分組(named group)

上面的示例使用簡單的、沒有命名的正規表達式組(通過圓括号)來捕獲URL中的值并以位置 參數傳遞給視圖。在更進階的用法中,可以使用命名的正規表達式組來捕獲URL中的值并以關鍵字 參數傳遞給視圖。

在Python正規表達式中,命名正規表達式組的文法是(?P<name>pattern),其中name是組的名稱,pattern是要比對的模式。

下面是以上Urlconf使用命名組的重寫:

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]      

這個實作與前面的示例完全相同,隻有一個細微的差别:捕獲的值作為關鍵字參數而不是位置參數傳遞給視圖函數。例如:

/articles/2005/03/    
   請求将調用views.month_archive(request, year='2005', month='03')函數
  /articles/2003/03/03/ 
   請求将調用函數views.article_detail(request, year='2003', month='03', day='03')。      

實際應用中,這意味你的URLconf會更加明晰且不容易産生參數順序問題的錯誤--你可以在你的視圖函數定義中重新安排參數的順序。當然,這些好處是以簡介為代價;有些開發人員認為命名組文法醜陋且繁瑣。

2.1.3 URLconf 在什麼上查找

URLconf在請求的URL上查找,将它當作一個普通的Python字元串。不包括GET和POST參數以及域名。

例如,http://www.example.com/myapp/請求中,URLconf将查找myapp/。

在http://www.example.com/myapp/?page=3請求中,URLconf仍将查找myapp/。

URLconf不檢查請求的方法。換句話将,所有的請求方法---同一個URL的POST、GET、HEAD等等--都将路由到相同的函數。

2.1.4 捕獲的參數永遠是字元串

每個捕獲的參數都作為一個普通的Python字元串傳遞給視圖,無論正規表達式使用的是什麼比對方式。例如,下面這行URLconf中:

url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),      

views.year_archive()的year參數将是一個字元串

2.1.5 指定視圖參數的預設值

有一個友善的小技巧是指定視圖參數的預設值。下面是一個URLconf和視圖的示例:

# URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$',views.page),
url(r'^blog/page(?P<num>[0-9]+)/$',views.page),
]
# View(in blog/views.py)
def page(request,num='1'):
  .....      

在上面的例子中,兩個URL模式指向同一個視圖views.page ---- 但是第一個模式不會從URL中捕獲任何值。如果第一個模式比對,page()函數将使用num參數的預設值‘1’。如果第二個模式比對,page()将使用正規表達式捕獲的num值。

2.1.6 Including other URLconfs

#At any point, your urlpatterns can “include” other URLconf modules. This
#essentially “roots” a set of URLs below other ones.

#For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs:
無論如何,您的urlpattern可以“包含”其他URLconf子產品。 這個
#根據“其他”下面的一組URL。

#例如,這是Django網站本身的URLconf的摘錄。
#它包括一些其他的URLconfs:
from django.conf.urls import include, url

urlpatterns = [
   url(r'^admin/', admin.site.urls),
   url(r'^blog/', include('blog.urls')),
]      

2.2 傳遞額外的選項給視圖函數(了解)

URLconfs具有一個鈎子,讓你傳遞一個Python字典作為額外的參數傳遞給視圖函數。

django.conf.urls.url()函數可以接受一個可選的第三個參數,它是一個字典,表示想要傳遞給視圖函數的額外關鍵字參數。

例如:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]      

在這個例子中,對于

/blog/2005/

請求,Django 将調用

views.year_archive(request, year='2005', foo='bar')

這個技術在Syndication 架構中使用,來傳遞中繼資料和選項給視圖。

2.3 name參數

urlpattern = [
url(r'^index',views.index,name=‘INDEX’),
]
###############
def index(req):
    if req.method=='POST':
        username=req.POST.get('username')
        password=req.POST.get('password')
        if username=='alex' and password=='123':
            return HttpResponse("登陸成功")

    return render(req,'index.html')
##############
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#     <form action="/index/" method="post">#}
     <form action="{% url 'INDEX' %}" method="post">
         使用者名:<input type="text" name="username">
         密碼:<input type="password" name="password">
         <input type="submit" value="submit">
     </form>
</body>
</html>      

三 編寫視圖

一個視圖函數,或者簡短來說叫做視圖,是一個簡單的Python函數,它接受web請求,并且傳回web響應。響應可以是一張網頁的HTML内容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖檔。。。是任何東西都可以。無論視圖本身包含什麼邏輯,都要響應傳回。代碼解除安裝哪裡也無所謂,隻要它在你的Python目錄下面。除此之外沒有更多的要求了---可以說‘沒有什麼神奇的地方’。為了能夠把代碼放在某個地方,慣例是把視圖放在叫做views.py的檔案中,然後把他放到你的項目或者應用目錄裡。

3.1 一個簡單的視圖

下面是一個傳回目前日期和時間作為HTML文檔的視圖:

from django.http import HttpResponse
import datetime
def current_datetime(req):
    now = datetime.datetime.now()
    html = "<html><body>Now time is %s.</body></html>"%now
    return HttpResponse(html)      

讓我們逐行閱讀上面代碼:

  • 首先,我們從django.http子產品導入了HttpResponse類,以及Python的datatime庫
  • 接着,我們定義了current_datetime函數。他是一個視圖函數。每個視圖函數都應接受HttpRequest對象作為第一個參數,一般叫做request。
  • 注意視圖函數的名稱不重要;不需要一個統一的命名方式來命名,以便讓Django識别它。我們将其命名為current_datetime,是因為這個名稱能夠精确的反映出它的功能。
  • 這個視圖會傳回一個HttpResponse對象,其中包含生成的響應。每個視圖函數都要傳回HttpResponse對象

'''

http請求-響應過程中有兩個核心對象:

http請求對象:HttpRequest

http響應對象:HttpResponse

所在位置:django.http

3.2  快捷函數

3.2.1 render函數

---------------render(request, template_name[, context])
結合一個給定的模版和一個給定的上下文字典、并傳回一個渲染後的HttpResponse對象
參數:
    request:用于生成響應的請求對象。
    template_name:要使用的模版的完整名稱,可選的參數
    context:添加到模版上下文的一個字典。預設是一個空字典。如果字典中的某個值是可調用的,視圖将在渲染模版之前調用它。
    content_type: 生成的文檔要使用的MIME類型。預設為DEFAULT_CONTENT_TYPE設定的值。
    status:響應的狀态碼,預設為200.      

3.2.2 redirect函數

-----------------------------------url.py

 url(r"login",   views.login),
 url(r"yuan_back",   views.yuan_back),

-----------------------------------views.py
def login(req):
    if req.method=="POST":
        if 1:
            # return redirect("/yuan_back/")
            name="yuanhao"

            return render(req,"my backend.html",locals())

    return render(req,"login.html",locals())


def yuan_back(req):

    name="苑昊"

    return render(req,"my backend.html",locals())

-----------------------------------login.html

<form action="/login/" method="post">
    <p>姓名<input type="text" name="username"></p>
    <p>性别<input type="text" name="sex"></p>
    <p>郵箱<input type="text" name="email"></p>
    <p><input type="submit" value="submit"></p>
</form>
-----------------------------------my backend.html
<h1>使用者{{ name }}你好</h1>

#總結: render和redirect的差別:
#   1 if render的頁面需要模闆語言渲染,需要的将資料庫的資料加載到html,那麼所有的這一部分
#     除了寫在yuan_back的視圖函數中,必須還要寫在login中,代碼重複,沒有解耦.

#   2 the most important: url沒有跳轉到/yuan_back/,而是還在/login/,是以當重新整理後
#     又得重新登入.      

四 Template

4.1 模闆系統的介紹

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

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><bkdy>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代碼+邏輯控制代碼

4.2 模闆支援的文法

4.2.1  變量(使用雙大括号來引用變量)

----------------------------------Template和Context對象 
>>> python manange.py shell  (進入該django項目的環境)
>>> from django.template import Context, Template
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
'My name is Stephane.'


# 同一模闆,多個上下文,一旦有了模闆對象,你就可以通過它渲染多個context,無論何時我們都可以
# 像這樣使用同一模闆源渲染多個context,隻進行 一次模闆建立然後多次調用render()方法渲染會
# 更為高效:
# Low
for name in ('John', 'Julie', 'Pat'):
    t = Template('Hello, {{ name }}')
    print t.render(Context({'name': name}))

# Good
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
    print t.render(Context({'name': name}))      

Django 模闆解析非常快捷。 大部分的解析工作都是在背景通過對簡短正規表達式一次性調用來完成。 這和基于 XML 的模闆引擎形成鮮明對比,那些引擎承擔了 XML 解析器的開銷,且往往比 Django 模闆渲染引擎要慢上幾個數量級。

from django.shortcuts import render,HttpResponse
from django.template.loader import get_template #記得導入
# Create your views here.


import datetime
from django.template import Template,Context

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



# def current_time(req):

      #django模闆修改的視圖函數
#     now=datetime.datetime.now()
#     t=Template('<html><body>現在時刻是:<h1 style="color:red">{{current_date}}</h1></body></html>')
      #t=get_template('current_datetime.html')
#     c=Context({'current_date':now})
#     html=t.render(c)
#     return HttpResponse(html)

#另一種寫法(推薦)

def current_time(req):

    now=datetime.datetime.now()

    return render(req, 'current_datetime.html', {'current_date':now})      

4.2.2 深度變量的查找(萬能的句點号)

在到目前為止的例子中,我們通過 context 傳遞的簡單參數值主要是字元串,然而,模闆系統能夠非常簡潔地處理更加複雜的資料結構,例如list、dictionary和自定義的對象。在 Django 模闆中周遊複雜資料結構的關鍵是句點字元 (.)。

#最好是用幾個例子來說明一下。
# 首先,句點可用于通路清單索引,例如:

>>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
'Item 2 is carrots.'

#假設你要向模闆傳遞一個 Python 字典。 要通過字典鍵通路該字典的值,可使用一個句點:
>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
'Sally is 43 years old.'

#同樣,也可以通過句點來通路對象的屬性。 比方說, Python 的 datetime.date 對象有
#year 、 month 和 day 幾個屬性,你同樣可以在模闆中使用句點來通路這些屬性:

>>> from django.template import Template, Context
>>> import datetime
>>> d = datetime.date(1993, 5, 2)
>>> d.year
1993
>>> d.month
5
>>> d.day
2
>>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
>>> c = Context({'date': d})
>>> t.render(c)
'The month is 5 and the year is 1993.'

# 這個例子使用了一個自定義的類,示範了通過執行個體變量加一點(dots)來通路它的屬性,這個方法适
# 用于任意的對象。
>>> from django.template import Template, Context
>>> class Person(object):
...     def __init__(self, first_name, last_name):
...         self.first_name, self.last_name = first_name, last_name
>>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
>>> c = Context({'person': Person('John', 'Smith')})
>>> t.render(c)
'Hello, John Smith.'

# 點文法也可以用來引用對象的方法。 例如,每個 Python 字元串都有 upper() 和 isdigit()
# 方法,你在模闆中可以使用同樣的句點文法來調用它們:
>>> from django.template import Template, Context
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'}))
'123 -- 123 -- True'

# 注意這裡調用方法時并* 沒有* 使用圓括号 而且也無法給該方法傳遞參數;你隻能調用不需參數的
# 方法。      

4.2.3 變量的過濾器(filter)的使用

文法格式:      {{obj|filter:param}}      
# 1  add          :   給變量加上相應的值
   #
   # 2  addslashes   :    給變量中的引号前加上斜線
   #
   # 3  capfirst     :    首字母大寫
   #
   # 4  cut          :   從字元串中移除指定的字元
   #
   # 5  date         :   格式化日期字元串
   #
   # 6  default      :   如果值是False,就替換成設定的預設值,否則就是用本來的值
   #
   # 7  default_if_none:  如果值是None,就替換成設定的預設值,否則就使用本來的值      
#執行個體:

#value1="aBcDe"
{{ value1|upper }}<br>

#value2=5
{{ value2|add:3 }}<br>

#value3='he  llo wo r ld'
{{ value3|cut:' ' }}<br>

#import datetime
#value4=datetime.datetime.now()
{{ value4|date:'Y-m-d' }}<br>

#value5=[]
{{ value5|default:'空的' }}<br>

#value6='<a href="#">跳轉</a>'

{{ value6 }}

{% autoescape off %}
  {{ value6 }}
{% endautoescape %}

{{ value6|safe }}<br>

{{ value6|striptags }}

#value7='1234'
{{ value7|filesizeformat }}<br>
{{ value7|first }}<br>
{{ value7|length }}<br>
{{ value7|slice:":-1" }}<br>

#value8='http://www.baidu.com/?a=1&b=3'
{{ value8|urlencode }}<br>
    value9='hello I am yuan'      

 4.2.4 标簽(tag)的使用(使用大括号和百分比的組合來表示使用tag)

文法格式:    {% tags %}      

{% if %} 的使用

{% if %}标簽計算一個變量值,如果是‘True’,即它存在、不為空并且不是false的boolean值,系統則會顯示{% if %}和{% endif %}間的所有内容

{% if num >= 100 and 8 %}

    {% if num > 200 %}
        <p>num大于200</p>
    {% else %}
        <p>num大于100小于200</p>
    {% endif %}

{% elif num < 100%}
    <p>num小于100</p>

{% else %}
    <p>num等于100</p>

{% endif %}



{% if %} 标簽接受and,or或者not來測試多個變量值或者否定一個給定的變量
{% if %} 标簽不允許同一标簽裡同時出現and和or,否則邏輯容易産生歧義,例如下面的标簽是不合法的:

{% if obj1 and obj2 or obj3 %}       

{% for %}的使用

{% for %}标簽允許你按順序周遊一個序列中的各個元素,每次循環模闆系統都會渲染{% for %}和{% endfor %}之間的所有内容

<ul>
{% for obj in list %}
    <li>{{ obj.name }}</li>
{% endfor %}
</ul>


#在标簽裡添加reversed來反序循環清單:

    {% for obj in list reversed %}
    ...
    {% endfor %}

#{% for %}标簽可以嵌套:

    {% for country in countries %}
        <h1>{{ country.name }}</h1>
        <ul>
         {% for city in country.city_list %}
            <li>{{ city }}</li>
         {% endfor %}
        </ul>
    {% endfor %}


#系統不支援中斷循環,系統也不支援continue語句,{% for %}标簽内置了一個forloop模闆變量,
#這個變量含有一些屬性可以提供給你一些關于循環的資訊

1,forloop.counter表示循環的次數,它從1開始計數,第一次循環設為1:

    {% for item in todo_list %}
        <p>{{ forloop.counter }}: {{ item }}</p>
    {% endfor %}
2,forloop.counter0 類似于forloop.counter,但它是從0開始計數,第一次循環設為0
3,forloop.revcounter
4,forloop.revcounter0
5,forloop.first當第一次循環時值為True,在特别情況下很有用:

    
    {% for object in objects %}   
         {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}   
         {{ object }}   
        </li>  
    {% endfor %}  
    
# 富有魔力的forloop變量隻能在循環中得到,當模闆解析器到達{% endfor %}時forloop就消失了
# 如果你的模闆context已經包含一個叫forloop的變量,Django會用{% for %}标簽替代它
# Django會在for标簽的塊中覆寫你定義的forloop變量的值
# 在其他非循環的地方,你的forloop變量仍然可用


#{% empty %}

{{li }}
      {%  for i in li %}
          <li>{{ forloop.counter0 }}----{{ i }}</li>
      {% empty %}
          <li>this is empty!</li>
      {% endfor %}

#         [11, 22, 33, 44, 55]
#            0----11
#            1----22
#            2----33
#            3----44
#            4----55      

csrf_token标簽

用于生成csrf_token的标簽,用于防治跨站攻擊驗證。 其實,這裡是會生成一個input标簽,和其他表單标簽一起送出給背景的。

{% url %}

引用路由配置的位址

<form action="{% url "bieming"%}" >
          <input type="text">
          <input type="submit"value="送出">
          {%csrf_token%}
</form>      

{% with %}

用更簡單的變量名替代複雜的變量名

{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}      

加載标簽庫:自定義filter和simple_tag

a、在app中建立templatetags子產品(必須的)

b、建立任意 .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


@register.simple_tag
def simple_tag_multi(v1,v2):
    return  v1 * v2


@register.simple_tag
def my_input(id,arg):
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)      

c、在使用自定義simple_tag和filter的html檔案中導入之前建立的 my_tags.py :{% load my_tags %}

d、使用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 %}      

e、在settings中的INSTALLED_APPS配置目前app,不然django無法找到自定義的simple_tag.

注意:

filter可以用在if等語句後,simple_tag不可以

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

extend模闆繼承

到目前為止,我們的模闆範例都隻是些零星的 HTML 片段,但在實際應用中,你将用 Django 模闆系統來建立整個 HTML 頁面。 這就帶來一個常見的 Web 開發問題: 在整個網站中,如何減少共用頁面區域(比如站點導航)所引起的重複和備援代碼?Django 解決此類問題的首選方法是使用一種優雅的政策—— 模闆繼承 。

本質上來說,模闆繼承就是先構造一個基礎架構模闆,而後在其子模闆中對它所包含站點公用部分和定義塊進行重載。

讓我們通過修改 current_datetime.html 檔案,為 current_datetime 建立一個更加完整的模闆來體會一下這種做法:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>The current time</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    <p>It is now {{ current_date }}.</p>
 
    <hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>      

這看起來很棒,但如果我們要為 hours_ahead 視圖建立另一個模闆會發生什麼事情呢?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>Future time</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
 
    <hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>       

Django 的模闆繼承系統解決了這些問題。 你可以将其視為伺服器端 include 的逆向思維版本。 你可以對那些不同 的代碼段進行定義,而不是 共同 代碼段。

第一步是定義 基礎模闆,該架構之後将由子模闆所繼承。 以下是我們目前所講述範例的基礎模闆:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    {% block content %}{% endblock %}
    {% block footer %}
    <hr>
    <p>Thanks for visiting my site.</p>
    {% endblock %}
</body>
</html>      

這個叫做 base.html 的模闆定義了一個簡單的 HTML 架構文檔,我們将在本站點的所有頁面中使用。 子模闆的作用就是重載、添加或保留那些塊的内容。 (如果你一直按順序學習到這裡,儲存這個檔案到你的template目錄下,命名為 base.html .)

我們使用模闆标簽: {% block %} 。 所有的 {% block %} 标簽告訴模闆引擎,子模闆可以重載這些部分。 每個{% block %}标簽所要做的是告訴模闆引擎,該模闆下的這一塊内容将有可能被子模闆覆寫。

現在我們已經有了一個基本模闆,我們可以修改 current_datetime.html 模闆來 使用它:

{% extends "base.html" %}
 
{% block title %}The current time{% endblock %}
 
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}      

再為 hours_ahead 視圖建立一個模闆,看起來是這樣的:

{% extends "base.html" %}
 
{% block title %}Future time{% endblock %}
 
{% block content %}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{% endblock %}      

看起來很漂亮是不是? 每個模闆隻包含對自己而言 獨一無二 的代碼。 無需多餘的部分。 如果想進行站點級的設計修改,僅需修改 base.html ,所有其它模闆會立即反映出所作修改。

以下是其工作方式:

      在加載 current_datetime.html 模闆時,模闆引擎發現了 {% extends %} 标簽, 注意到該模闆是一個子模闆。 模闆引擎立即裝載其父模闆,即本例中的 base.html 。此時,模闆引擎注意到 base.html 中的三個 {% block %} 标簽,并用子模闆的内容替換這些 block 。是以,引擎将會使用我們在 { block title %} 中定義的标題,對 {% block content %} 也是如此。 是以,網頁标題一塊将由{% block title %}替換,同樣地,網頁的内容一塊将由 {% block content %}替換。

     注意由于子模闆并沒有定義 footer 塊,模闆系統将使用在父模闆中定義的值。 父模闆 {% block %} 标簽中的内容總是被當作一條退路。繼承并不會影響到模闆的上下文。 換句話說,任何處在繼承樹上的模闆都可以通路到你傳到模闆中的每一個模闆變量。你可以根據需要使用任意多的繼承次數。 使用繼承的一種常見方式是下面的三層法:

<1> 建立 base.html 模闆,在其中定義站點的主要外觀感受。 這些都是不常修改甚至從不修改的部分。
   <2> 為網站的每個區域建立 base_SECTION.html 模闆(例如, base_photos.html 和 base_forum.html )。這些模闆對base.html 進行拓展,
       并包含區域特定的風格與設計。
   <3> 為每種類型的頁面建立獨立的模闆,例如論壇頁面或者圖檔庫。 這些模闆拓展相應的區域模闆。      
<1>如果在模闆中使用 {% extends %} ,必須保證其為模闆中的第一個模闆标記。 否則,模闆繼承将不起作用。

 <2>一般來說,基礎模闆中的 {% block %} 标簽越多越好。 記住,子模闆不必定義父模闆中所有的代碼塊,是以
    你可以用合理的預設值對一些代碼塊進行填充,然後隻對子模闆所需的代碼塊進行(重)定義。 俗話說,鈎子越
    多越好。

 <3>如果發覺自己在多個模闆之間拷貝代碼,你應該考慮将該代碼段放置到父模闆的某個 {% block %} 中。
    如果你需要通路父模闆中的塊的内容,使用 {{ block.super }}這個标簽吧,這一個魔法變量将會表現出父模
    闆中的内容。 如果隻想在上級代碼塊基礎上添加内容,而不是全部重載,該變量就顯得非常有用了。

 <4>不允許在同一個模闆中定義多個同名的 {% block %} 。 存在這樣的限制是因為block 标簽的工作方式是雙向的。
    也就是說,block 标簽不僅挖了一個要填的坑,也定義了在父模闆中這個坑所填充的内容。如果模闆中出現了兩個
    相同名稱的 {% block %} 标簽,父模闆将無從得知要使用哪個塊的内容。      

繼續閱讀