Django-MTV

MTV模型

Django的MTV分別代表:

  • Model(模型):負責業(yè)務對象與數(shù)據(jù)庫的對象(ORM)
  • Template(模版):負責如何把頁面展示給用戶
  • View(視圖):負責業(yè)務邏輯,并在適當?shù)臅r候調(diào)用Model和Template

此外,Django還有一個urls分發(fā)器,它的作用是將一個個URL的頁面請求分發(fā)給不同的view處理,view再調(diào)用相應的Model和Template

img

Django基本命令

1 下載django

pip3 install django

2、創(chuàng)建一個django project

django-admin.py startproject mysite

當前目錄下會生成mysite的工程,目錄結(jié)構(gòu)如下:

img
  • manage.py ----- Django項目里面的工具,通過它可以調(diào)用django shell和數(shù)據(jù)庫等。
  • settings.py ---- 包含了項目的默認設置,包括數(shù)據(jù)庫信息,調(diào)試標志以及其他一些工作的變量。
  • urls.py ----- 負責把URL模式映射到應用程序。

3、在mysite目錄下創(chuàng)建應用

python manage.py startapp blog
img

4、啟動django項目

python manage.py runserver 8080

這樣我們的django就啟動起來了!當我們訪問:http://127.0.0.1:8080/時就可以看到:

img

5、同步更改數(shù)據(jù)庫表或字段

python manage.py syncdb
     
     注意:Django 1.7.1 及以上的版本需要用以下命令
     python manage.py makemigrations
     python manage.py migrate

這種方法可以創(chuàng)建表,當你在models.py中新增了類時,運行它就可以自動在數(shù)據(jù)庫中創(chuàng)建表了,不用手動創(chuàng)建。

6、清空數(shù)據(jù)庫

python manage.py flush

此命令會詢問是 yes 還是 no, 選擇 yes 會把數(shù)據(jù)全部清空掉,只留下空表。

7、創(chuàng)建超級管理員

python manage.py createsuperuser
     
    # 按照提示輸入用戶名和對應的密碼就好了郵箱可以留空,用戶名和密碼必填
    # 修改 用戶密碼可以用:
    python manage.py changepassword username

8、Django 項目環(huán)境終端

python manage.py shell

這個命令和 直接運行 python 進入 shell 的區(qū)別是:你可以在這個 shell 里面調(diào)用當前項目的 models.py 中的 API,對于操作數(shù)據(jù)的測試非常方便。

9、Django 項目環(huán)境終端

python manage.py dbshell

Django 會自動進入在settings.py中設置的數(shù)據(jù)庫,如果是 MySQL 或 postgreSQL,會要求輸入數(shù)據(jù)庫用戶密碼。

在這個終端可以執(zhí)行數(shù)據(jù)庫的SQL語句。如果您對SQL比較熟悉,可能喜歡這種方式。

10、更多命令

python manage.py     查看所有的命令,忘記子名稱的時候特別有用。

11 靜態(tài)文件配置

概述:

     靜態(tài)文件交由Web服務器處理,Django本身不處理靜態(tài)文件。簡單的處理邏輯如下(以nginx為例):

              URI請求-----> 按照Web服務器里面的配置規(guī)則先處理,以nginx為例,主要求配置在nginx.
                             conf里的location

                         |---------->如果是靜態(tài)文件,則由nginx直接處理

                         |---------->如果不是則交由Django處理,Django根據(jù)urls.py里面的規(guī)則進行匹配

    以上是部署到Web服務器后的處理方式,為了便于開發(fā),Django提供了在開發(fā)環(huán)境的對靜態(tài)文件的處理機制,方法是這樣:

static配置:

STATIC主要指的是如css,js,images這樣文件:

STATIC_URL = '/static/'      # 別名
STATICFILES_DIRS = (
            os.path.join(BASE_DIR,"static"),  #實際名 ,即實際文件夾的名字
        )

'''

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

注意點2:
 STATICFILES_DIRS = (
    ("app01",os.path.join(BASE_DIR, "app01/statics")),
        )

 <script src="/static/app01/jquery.js"></script>

'''

have a try:

http://127.0.0.1:8000/static/jquery.js

media配置:

# in settings:
MEDIA_URL="/media/"
MEDIA_ROOT=os.path.join(BASE_DIR,"app01","media","upload")

# in urls:
from django.views.static import serve
url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),

have a try:

http://127.0.0.1:8000/media/1.png
        '''
        靜態(tài)文件的處理又包括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/"
        在開發(fā)階段,media的處理由django處理:

           訪問http://localhost/data/abc/a.png就是訪問c:\temp\media\photo\abc\a.png

           在模板里面這樣寫<img src="/media/abc/a.png">

           在部署階段最大的不同在于你必須讓web服務器來處理media文件,因此你必須在web服務器中配置,
           以便能讓web服務器能訪問media文件
           以nginx為例,可以在nginx.conf里面這樣:

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

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

視圖層之路由配置系統(tǒng)(views)

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

urlpatterns = [
    url(正則表達式, views視圖函數(shù),參數(shù),別名),
]

參數(shù)說明:
    一個正則表達式字符串
    一個可調(diào)用對象,通常為一個視圖函數(shù)或一個指定視圖函數(shù)路徑的字符串
    可選的要傳遞給視圖函數(shù)的默認參數(shù)(字典形式)
    一個可選的name參數(shù)

2.1 URLconf的正則字符串參數(shù)

2.1.1 簡單配置

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
NOTE:
    1 一旦匹配成功則不再繼續(xù)
    2 若要從URL 中捕獲一個值,只需要在它周圍放置一對圓括號。
    3 不需要添加一個前導的反斜杠,因為每個URL 都有。例如,應該是^articles 而不是 ^/articles。
    4 每個正則表達式前面的'r' 是可選的但是建議加上。

一些請求的例子:
    /articles/2005/3/ 不匹配任何URL 模式,因為列表中的第三個模式要求月份應該是兩個數(shù)字。
    /articles/2003/ 將匹配列表中的第一個模式不是第二個,因為模式按順序匹配,第一個會首先測試是否匹配。
    /articles/2005/03/ 請求將匹配列表中的第三個模式。Django 將調(diào)用函數(shù)  views.month_archive(request, '2005', '03')。
#設置項是否開啟URL訪問地址后面不為/跳轉(zhuǎn)至帶有/的路徑
APPEND_SLASH=True

2.1.2 有名分組(named group)

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

在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),
]

這個實現(xiàn)與前面的示例完全相同,只有一個細微的差別:捕獲的值作為關鍵字參數(shù)而不是位置參數(shù)傳遞給視圖函數(shù)。例如:

/articles/2005/03/    
請求將調(diào)用views.month_archive(request, year='2005', month='03')函數(shù)
/articles/2003/03/03/ 
請求將調(diào)用函數(shù)views.article_detail(request, year='2003', month='03', day='03')。

在實際應用中,這意味你的URLconf 會更加明晰且不容易產(chǎn)生參數(shù)順序問題的錯誤 —— 你可以在你的視圖函數(shù)定義中重新安排參數(shù)的順序。

當然,這些好處是以簡潔為代價;有些開發(fā)人員認為命名組語法丑陋而繁瑣。

2.1.3 URLconf 在什么上查找

URLconf 在請求的URL 上查找,將它當做一個普通的Python 字符串。不包括GET和POST參數(shù)以及域名。

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

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

URLconf 不檢查請求的方法。換句話講,所有的請求方法 —— 同一個URL的POST、GET、HEAD等等 —— 都將路由到相同的函數(shù)。

2.1.4 捕獲的參數(shù)永遠是字符串

每個捕獲的參數(shù)都作為一個普通的Python 字符串傳遞給視圖,無論正則表達式使用的是什么匹配方式。例如,下面這行URLconf 中:

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

views.year_archive()year 參數(shù)將是一個字符串

2.1.5 指定視圖參數(shù)的默認值

有一個方便的小技巧是指定視圖參數(shù)的默認值。 下面是一個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() 函數(shù)將使用num參數(shù)的默認值"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:


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

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

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

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

例如:

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 將調(diào)用views.year_archive(request, year='2005', foo='bar')。

這個技術(shù)在Syndication 框架中使用,來傳遞元數(shù)據(jù)和選項給視圖。

2.3 URL 的反向解析

在使用Django 項目時,一個常見的需求是獲得URL 的最終形式,以用于嵌入到生成的內(nèi)容中(視圖中和顯示給用戶的URL等)或者用于處理服務器端的導航(重定向等)。

人們強烈希望不要硬編碼這些URL(費力、不可擴展且容易產(chǎn)生錯誤)或者設計一種與URLconf 毫不相關的專門的URL 生成機制,因為這樣容易導致一定程度上產(chǎn)生過期的URL。

換句話講,需要的是一個DRY 機制。除了其它有點,它還允許設計的URL 可以自動更新而不用遍歷項目的源代碼來搜索并替換過期的URL。

獲取一個URL 最開始想到的信息是處理它視圖的標識(例如名字),查找正確的URL 的其它必要的信息有視圖參數(shù)的類型(位置參數(shù)、關鍵字參數(shù))和值。

Django 提供一個辦法是讓URL 映射是URL 設計唯一的地方。你填充你的URLconf,然后可以雙向使用它:

  • 根據(jù)用戶/瀏覽器發(fā)起的URL 請求,它調(diào)用正確的Django 視圖,并從URL 中提取它的參數(shù)需要的值。
  • 根據(jù)Django 視圖的標識和將要傳遞給它的參數(shù)的值,獲取與之關聯(lián)的URL。

第一種方式是我們在前面的章節(jié)中一直討論的用法。第二種方式叫做反向解析URL、反向URL 匹配、反向URL 查詢或者簡單的URL 反查。

在需要URL 的地方,對于不同層級,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url 模板標簽。
  • 在Python 代碼中:使用django.core.urlresolvers.reverse() 函數(shù)。
  • 在更高層的與處理Django 模型實例相關的代碼中:使用get_absolute_url() 方法。

考慮下面的URLconf:

from django.conf.urls import url

from . import views

urlpatterns = [
    #...
    url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    #...
]

根據(jù)這里的設計,某一年nnnn對應的歸檔的URL是/articles/nnnn/。

你可以在模板的代碼中使用下面的方法獲得它們:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

在Python 代碼中,這樣使用:

from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

如果出于某種原因決定按年歸檔文章發(fā)布的URL應該調(diào)整一下,那么你將只需要修改URLconf 中的內(nèi)容。

在某些場景中,一個視圖是通用的,所以在URL 和視圖之間存在多對一的關系。對于這些情況,當反查URL 時,只有視圖的名字還不夠。

2.4 命名URL 模式

為了完成上面例子中的URL 反查,你將需要使用命名的URL 模式。URL 的名稱使用的字符串可以包含任何你喜歡的字符。不只限制在合法的Python 名稱。

當命名你的URL 模式時,請確保使用的名稱不會與其它應用中名稱沖突。如果你的URL 模式叫做comment,而另外一個應用中也有一個同樣的名稱,當你在模板中使用這個名稱的時候不能保證將插入哪個URL。

在URL 名稱中加上一個前綴,比如應用的名稱,將減少沖突的可能。我們建議使用myapp-comment 而不是comment。

2.5 CBV

url(r'^login.html$', views.Login.as_view()),
 
============================
from django.views import View
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')

視圖層之視圖函數(shù)(views)

一個視圖函數(shù),簡稱視圖,是一個簡單的Python 函數(shù),它接受Web請求并且返回Web響應。響應可以是一張網(wǎng)頁的HTML內(nèi)容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片. . . 是任何東西都可以。無論視圖本身包含什么邏輯,都要返回響應。代碼寫在哪里也無所謂,只要它在你的Python目錄下面。除此之外沒有更多的要求了——可以說“沒有什么神奇的地方”。為了將代碼放在某處,約定是將視圖放置在項目或應用程序目錄中的名為views.py的文件中。

一個簡單的視圖

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

from django.http import HttpResponse
import datetime

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

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

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

  • 接著,我們定義了current_datetime函數(shù)。它就是視圖函數(shù)。每個視圖函數(shù)都使用HttpRequest對象作為第一個參數(shù),并且通常稱之為request

    注意,視圖函數(shù)的名稱并不重要;不需要用一個統(tǒng)一的命名方式來命名,以便讓Django識別它。我們將其命名為current_datetime,是因為這個名稱能夠精確地反映出它的功能。

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

img

HttpRequest對象

屬性:

'''
path:       請求頁面的全路徑,不包括域名

method:     請求中使用的HTTP方法的字符串表示。全大寫表示。例如

               if  req.method=="GET":

                         do_something()

               elif req.method=="POST":

                         do_something_else()

GET:         包含所有HTTP GET參數(shù)的類字典對象

POST:       包含所有HTTP POST參數(shù)的類字典對象

COOKIES:     包含所有cookies的標準Python字典對象;keys和values都是字符串。

FILES:      包含所有上傳文件的類字典對象;FILES中的每一個Key都是<input type="file" name="" />標簽中
             name屬性的值,F(xiàn)ILES中的每一個value同時也是一個標準的python字典對象,包含下面三個Keys:

             filename:      上傳文件名,用字符串表示
             content_type:   上傳文件的Content Type
             content:       上傳文件的原始內(nèi)容


user:       是一個django.contrib.auth.models.User對象,代表當前登陸的用戶。如果訪問用戶當前
             沒有登陸,user將被初始化為django.contrib.auth.models.AnonymousUser的實例。你
             可以通過user的is_authenticated()方法來辨別用戶是否登陸:
             if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware
             時該屬性才可用

session:    唯一可讀寫的屬性,代表當前會話的字典對象;自己有激活Django中的session支持時該屬性才可用。

'''

方法:

get_full_path()
    鍵值對的值是多個的時候,比如checkbox類型的input標簽,select標簽,需要用:request.POST.getlist("hobby")

render 函數(shù)

render(request, template_name[, context])

結(jié)合一個給定的模板和一個給定的上下文字典,并返回一個渲染后的 HttpResponse 對象。

參數(shù):
     request: 用于生成響應的請求對象。

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

     context:添加到模板上下文的一個字典。默認是一個空字典。如果字典中的某個值是可調(diào)用的,視圖將在渲染模板之前調(diào)用它。

     content_type:生成的文檔要使用的MIME類型。默認為DEFAULT_CONTENT_TYPE 設置的值。

     status:響應的狀態(tài)碼。默認為200。

redirect 函數(shù)

參數(shù)可以是:

  • 一個模型:將調(diào)用模型的get_absolute_url() 函數(shù)
  • 一個視圖,可以帶有參數(shù):將使用urlresolvers.reverse 來反向解析名稱
  • 一個絕對的或相對的URL,將原封不動的作為重定向的位置。

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

示例:你可以用多種方式使用redirect() 函數(shù)。

傳遞一個對象

將調(diào)用get_absolute_url() 方法來獲取重定向的URL:

from django.shortcuts import redirect
 
def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object)

傳遞一個視圖的名稱

可以帶有位置參數(shù)和關鍵字參數(shù);將使用reverse() 方法反向解析URL:

def my_view(request):
    ...
    return redirect('some-view-name', foo='bar')

傳遞要重定向的一個硬編碼的URL

def my_view(request):
    ...
    return redirect('/some/url/')

也可以是一個完整的URL:

def my_view(request):
    ...
    return redirect('http://example.com/')

默認情況下,redirect() 返回一個臨時重定向。以上所有的形式都接收一個permanent 參數(shù);如果設置為True,將返回一個永久的重定向:

def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object, permanent=True)  

跳轉(zhuǎn)(重定向)應用

-----------------------------------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的區(qū)別:

1、 if 頁面需要模板語言渲染,需要的將數(shù)據(jù)庫的數(shù)據(jù)加載到html,那么render方法則不會顯示這一部分。

2、 the most important: url沒有跳轉(zhuǎn)到/yuan_back/,而是還在/login/,所以當刷新后又得重新登錄。

模板層(template)

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

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

盡管這種技術(shù)便于解釋視圖是如何工作的,但直接將HTML硬編碼到你的視圖里卻并不是一個好主意。 讓我們來看一下為什么:

  • 對頁面設計進行的任何改變都必須對 Python 代碼進行相應的修改。 站點設計的修改往往比底層 Python 代碼的修改要頻繁得多,因此如果可以在不進行 Python 代碼修改的情況下變更設計,那將會方便得多。
  • Python 代碼編寫和 HTML 設計是兩項不同的工作,大多數(shù)專業(yè)的網(wǎng)站開發(fā)環(huán)境都將他們分配給不同的人員(甚至不同部門)來完成。 設計者和HTML/CSS的編碼人員不應該被要求去編輯Python的代碼來完成他們的工作。
  • 程序員編寫 Python代碼和設計人員制作模板兩項工作同時進行的效率是最高的,遠勝于讓一個人等待另一個人完成對某個既包含 Python又包含 HTML 的文件的編輯工作。

基于這些原因,將頁面的設計和Python的代碼分離開會更干凈簡潔更容易維護。 我們可以使用 Django的 模板系統(tǒng) (Template System)來實現(xiàn)這種模式,這就是本章要具體討論的問題。

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

模版包括在使用時會被值替換掉的 變量,和控制模版邏輯的 標簽。

def current_time(req):
    import datetime
    now=datetime.datetime.now()
    return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})

模板語法之變量

在 Django 模板中遍歷復雜數(shù)據(jù)結(jié)構(gòu)的關鍵是句點字符 . (深度查詢)

語法: {{var_name}}

views:

def index(request):
    import datetime
    s="hello"
    l=[111,222,333]    # 列表
    dic={"name":"yuan","age":18}  # 字典
    date = datetime.date(1993, 5, 2)   # 日期對象
 
    class Person(object):
        def __init__(self,name):
            self.name=name
 
    person_yuan=Person("yuan")  # 自定義類對象
    person_egon=Person("egon")
    person_alex=Person("alex")
    person_list=[person_yuan,person_egon,person_alex]
 
    return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})  

**template: **

<h4>{{s}}</h4>
<h4>列表:{{ l.0 }}</h4>
<h4>列表:{{ l.2 }}</h4>
<h4>字典:{{ dic.name }}</h4>
<h4>日期:{{ date.year }}</h4>
<h4>類對象列表:{{ person_list.0.name }}</h4>

注意:句點符也可以用來引用對象的方法(無參數(shù)方法)。

<h4>字典:{{ dic.name.upper }}</h4>

模板之過濾器

語法:

{{obj|filter1:param|filter2:param}}
default 
如果一個變量是false或者為空,使用給定的默認值。否則,使用變量的值。例如:
{{ value|default:"nothing" }}

length
返回值的長度。它對字符串和列表都起作用。例如:
{{ value|length }}

filesizeformat
將值格式化為一個 “人類可讀的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }}

date
如果 value=datetime.datetime.now()
{{ value|date:"Y-m-d" }}  

slice
如果 value="hello world"
{{ value|slice:"2:-1" }}

truncatechars(truncatewords)
如果字符串字符多于指定的字符(單詞)數(shù)量,那么會被截斷。截斷的字符串將以可翻譯的省略號序列(“...”)結(jié)尾。
參數(shù):要截斷的字符數(shù)
例如: {{ value|truncatechars:9 }}
如果value是“Joel isasadads dsad”是,輸出將為“Joel i ...”。

safe
Django的模板中會對HTML標簽和JS等語法標簽進行自動轉(zhuǎn)義,原因顯而易見,這樣是為了安全。但是有的時候我們可能不希望這些HTML元素被轉(zhuǎn)義,比如我們做一個內(nèi)容管理系統(tǒng),后臺添加的文章中是經(jīng)過修飾的,這些修飾可能是通過一個類似于FCKeditor編輯加注了HTML修飾符的文本,如果自動轉(zhuǎn)義的話顯示的就是保護HTML標簽的源文件。為了在Django中關閉HTML的自動轉(zhuǎn)義有兩種方式,如果是一個單獨的變量我們可以通過過濾器“|safe”的方式告訴Django這段代碼是安全的不必轉(zhuǎn)義。比如:
value="<a href="">點擊</a>"
{{ value|safe}}

參考手冊

http://python.usyiyi.cn/translate/django_182/ref/templates/builtins.html#ref-templates-builtins-tags

模板之標簽

標簽看起來像是這樣的: {% tag %}。標簽比變量更加復雜:一些在輸出中創(chuàng)建文本,一些通過循環(huán)或邏輯來控制流程,一些加載其后的變量將使用到的額外信息到模版中。

一些標簽需要開始和結(jié)束標簽 (例如{% tag %} ...標簽 內(nèi)容 ... {% endtag %})。

for標簽

遍歷每一個元素:

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

可以利用{% for obj in list reversed %}反向完成循環(huán)。

遍歷一個字典:

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

注:循環(huán)序號可以通過{{forloop}}顯示

forloop.counter         The current iteration of the loop (1-indexed)
forloop.counter0    The current iteration of the loop (0-indexed)
forloop.revcounter  The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0 The number of iterations from the end of the loop (0-indexed)
forloop.first           True if this is the first time through the loop
forloop.last            True if this is the last time through the loop

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值),對應的內(nèi)容塊會輸出。

{% if num > 100 or num < 0 %}
    <p>無效</p>
{% elif num > 80 and num < 100 %}
    <p>優(yōu)秀</p>
{% else %}
    <p>湊活吧</p>
{% endif %}

with

使用一個簡單地名字緩存一個復雜的變量,當你需要使用一個“昂貴的”方法(比如訪問數(shù)據(jù)庫)很多次的時候是非常有用的

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

csrf_token

這個標簽用于跨站請求偽造保護

自定義標簽和過濾器

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

  2. 在app中創(chuàng)建templatetags模塊(模塊名只能是templatetags)

  3. 創(chuàng)建任意 .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)
    

    ?

  4. 在使用自定義simple_tag和filter的html文件中導入之前創(chuàng)建的 my_tags.py

    {% load my_tags %} 
    

    ?

  5. 使用simple_tag和filter(如何調(diào)用)

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

注意:filter可以用在if等語句后,simple_tag不可以

{% if num|filter_multi:30 > 100 %}
    {{ num|filter_multi:30 }}
{% endif %}
對比過濾器和標簽的使用
    過濾器函數(shù)的參數(shù)只能有兩個,自定義標簽無參數(shù)限制
    過濾器可以與邏輯標簽共同使用,自定義標簽不可以

模板繼承 (extend)

Django模版引擎中最強大也是最復雜的部分就是模版繼承了。模版繼承可以讓您創(chuàng)建一個基本的“骨架”模版,它包含您站點中的全部元素,并且可以定義能夠被子模版覆蓋的 blocks 。

通過從下面這個例子開始,可以容易的理解模版繼承:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}My amazing site{%/span> 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骨架?!白幽0妗钡墓ぷ魇怯盟鼈兊膬?nèi)容填充空的blocks。

在這個例子中, block 標簽定義了三個可以被子模版內(nèi)容填充的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 標簽是這里的關鍵。它告訴模版引擎,這個模版“繼承”了另一個模版。當模版系統(tǒng)處理這個模版時,首先,它將定位父模版——在此例中,就是“base.html”。

那時,模版引擎將注意到 base.html 中的三個 block 標簽,并用子模版中的內(nèi)容來替換這些block。根據(jù) 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,所以系統(tǒng)使用了父模版中的值。父模版的 {% block %} 標簽中的內(nèi)容總是被用作備選內(nèi)容(fallback)。

這種方式使代碼得到最大程度的復用,并且使得添加內(nèi)容到共享的內(nèi)容區(qū)域更加簡單,例如,部分范圍內(nèi)的導航。

這里是使用繼承的一些提示:

  • 如果你在模版中使用 {% extends %} 標簽,它必須是模版中的第一個標簽。其他的任何情況下,模版繼承都將無法工作。

  • 在base模版中設置越多的 {% block %} 標簽越好。請記住,子模版不必定義全部父模版中的blocks,所以,你可以在大多數(shù)blocks中填充合理的默認內(nèi)容,然后,只定義你需要的那一個。多一點鉤子總比少一點好。

  • 如果你發(fā)現(xiàn)你自己在大量的模版中復制內(nèi)容,那可能意味著你應該把內(nèi)容移動到父模版中的一個 {% 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 標簽。這個限制的存在是因為block標簽的作用是“雙向”的。這個意思是,block標簽不僅提供了一個坑去填,它還在 父模版中定義了填坑的內(nèi)容。如果在一個模版中有兩個名字一樣的 block 標簽,模版的父模版將不知道使用哪個block的內(nèi)容。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容