整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線:

          「Django框架」-模板

          「Django框架」-模板

          源于公眾號(hào):Python野路子

          一、模板介紹


          我們之前學(xué)習(xí)的,都是在視圖函數(shù)直接返回文本,在實(shí)際中我們更多的是帶有樣式的HTML代碼,這樣可以讓瀏覽器渲染出非常漂亮的頁(yè)面,目前市面上有非常多的模板系統(tǒng),其中最常用的是DTLJinja2DTL(Django Template Language),也就是Django自帶的模板語(yǔ)言,當(dāng)然也可以配置Django支持Jinja2,但是作為Django內(nèi)置的模板語(yǔ)言,不會(huì)產(chǎn)生一些不兼容的情況,最好還是使用內(nèi)置的。

          1. DTL與普通的HTML文件區(qū)別

          DTL模板是一種帶有特殊語(yǔ)法的HTML文件,這個(gè)HTML文件可以被Django編譯,可以傳遞參數(shù)進(jìn)去,實(shí)現(xiàn)數(shù)據(jù)動(dòng)態(tài)化,在編譯完成后,生成一個(gè)普通的HTML文件,然后發(fā)送給客戶端。

          2. 模板渲染

          可以使用render函數(shù)進(jìn)行渲染,將數(shù)據(jù)渲染到指定的HTML模板中。

          我們?cè)谥暗幕A(chǔ)上,再新建一個(gè)articleapp,除了剛開(kāi)始第一個(gè)應(yīng)用,我們?cè)?span style="color: #1E6BB8; --tt-darkmode-color: #1E6BB8;">pycharm創(chuàng)建項(xiàng)目的時(shí)候,填了app名字,pycharm會(huì)自動(dòng)幫我們創(chuàng)建應(yīng)用,后續(xù)如果還要再新建應(yīng)用,我們都要使用命令方式才能新建app


          應(yīng)用創(chuàng)建完成了,接下來(lái)我們需要在配置文件settings.py里面注冊(cè)應(yīng)用app

          INSTALLED_APPS = [
              'django.contrib.admin',
              'django.contrib.auth',
              'django.contrib.contenttypes',
              'django.contrib.sessions',
              'django.contrib.messages',
              'django.contrib.staticfiles',
              'user.apps.UserConfig',   # 使用pycharm創(chuàng)建的應(yīng)用,pycharm會(huì)自動(dòng)注冊(cè)
              'article'  # 手工命令方式創(chuàng)建的應(yīng)用app,需要手工在這注冊(cè)應(yīng)用!
          ]
          

          路由和視圖代碼:

          # 主urls.py
          path('article/', include('article.urls', namespace='article'))
              
          # 應(yīng)用urls.py,創(chuàng)建的應(yīng)用這個(gè)文件不會(huì)自動(dòng)生成,需要我們新建
          
          from django.urls import path
          from . import views
          
          app_name = 'article'
          urlpatterns = [
              path('index/', views.index, name='index')
          
          ]
          
          # 視圖views.py
          from django.shortcuts import render
          
          def index(request):
              return render(request, 'index.html')  # 使用render渲染模板
          

          模板文件,項(xiàng)目根目錄下templates目錄(若沒(méi)有自動(dòng)生成,則手工新建此文件夾)下新建index.html模板文件。

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              <h2>文章首頁(yè)</h2>
          </body>
          </html>
          

          查看效果:

          使用render函數(shù)將模板成功渲染出來(lái)了。

          3. 模板文件查找路徑

          在項(xiàng)目的settings.py配置文件中,有一個(gè)TEMPLATES配置。

          TEMPLATES = [
              {
                  # 模板引擎,就是Django內(nèi)置的模板引擎,
                  # 若要配置為Jinja2:django.template.backends.jinja2.Jinja2
                  'BACKEND': 'django.template.backends.django.DjangoTemplates',
                  # BASE_DIR,項(xiàng)目根目錄路徑下的templates查找
                  #'DIRS': [os.path.join(BASE_DIR, 'templates')] # Django2中使用
                  'DIRS': [BASE_DIR / 'templates'],  #  Django3中使用
                  ,
                  # 是否從app應(yīng)用下的templates下查找模板文件
                  'APP_DIRS': True,
                  'OPTIONS': {
                      # 模板中間件
                      'context_processors': [
                          'django.template.context_processors.debug',
                          'django.template.context_processors.request',
                          'django.contrib.auth.context_processors.auth',
                          'django.contrib.messages.context_processors.messages',
                      ],
                  },
              },
          ]
          

          這個(gè)配置包含了模板引擎的配置,這個(gè)配置包含了模板引擎的配置,模板查找路徑的配置,模板上下文的配置等,模板路徑可以2個(gè)地方配置。

          1. DIRS:這是一個(gè)列表,在這個(gè)列表中可以存放所有的模板路徑,以后在視圖中使用render渲染模板時(shí),就會(huì)從這個(gè)列表的路徑中查找模板。
          2. APP_DIRS:默認(rèn)為True,這個(gè)表示已經(jīng)在INSTALLED_APPS文件中注冊(cè)過(guò)的應(yīng)用app下的templates目錄下查找模板文件。
          3. 查找順序:比如代碼render(request,'index.html'),先會(huì)在DIRS這個(gè)列表中依次查找路徑下有沒(méi)有這個(gè)模板,如果有,就返回,如果沒(méi)有,則會(huì)先檢查當(dāng)前視圖所處的app是否已經(jīng)安裝,那么就先在當(dāng)前app下的templates目錄下查找模板,如果沒(méi)有找到,就會(huì)去其他注冊(cè)的app中繼續(xù)查找,如果所有路徑下都沒(méi)有找到,則會(huì)拋出TemplateDoesNotExist

          二、DTL模板語(yǔ)法

          1. 模板變量

          我們想要將后臺(tái)數(shù)據(jù)渲染到頁(yè)面上,這就需要用到模板變量。

          # 主urls.py
          path('article/', include('article.urls', namespace='article'))
          
          # 應(yīng)用urls.py
          path('index/', views.index, name='index')
          
          
          
          # 視圖views.py
          from django.shortcuts import render
          
          class Article:
              def __init__(self, title):
                  self.title = title
          
          
          def index(request):
              context = {
                  'msg': '模板變量',    # 字符串,
                  'article': Article('Django框架之模板文件'),    # 實(shí)例一個(gè)對(duì)象,
                  'author': {'name': 'admin'},    # 一個(gè)字典
                  'tag': ['python入門(mén)', 'python進(jìn)階', '數(shù)據(jù)庫(kù)']  # 列表或元組
              }
          
              return render(request, 'index.html', context=context)  # 傳入一個(gè)字典
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              <h2>文章首頁(yè)</h2>
              <p>{{ msg }}</p> <!-- 在模板中使用變量,需要將變量放到 {{ 變量 }} 中 -->
              <h3>{{ article.title }}</h3>  <!-- 要訪問(wèn)對(duì)象的屬性,通過(guò)"對(duì)象.屬性名" 訪問(wèn) -->
              <p>作者:{{ author.name }}</p>  <!-- 要訪問(wèn)字典key對(duì)應(yīng)值value,通過(guò)"字典.key" 訪問(wèn),不能[]形式 -->
              <ul>
                  <li>{{ tag.0 }}</li>  <!-- 要訪問(wèn)列表或者元組的元素,通過(guò)"列表.索引" 訪問(wèn) -->
                  <li>{{ tag.1 }}</li>
                  <li>{{ tag.2 }}</li>
              </ul>
          </body>
          </html>
          

          效果:


          在模板中使用變量:語(yǔ)法:{{變量名}} 1)命名由字母和數(shù)字以及下劃線組成,不能有空格和標(biāo)點(diǎn)符號(hào)。2)不要和python或django關(guān)鍵字重名。原因:如果data是一個(gè)字典,那么訪問(wèn)data.items將會(huì)訪問(wèn)data這個(gè)字典的key名為items的值,而不會(huì)訪問(wèn)字典的items方法。

          2. 模板標(biāo)簽

          標(biāo)簽語(yǔ)法:{% 標(biāo)簽名稱(chēng) %} {% 結(jié)束標(biāo)簽名稱(chēng) %}

          例:{%tag%} {%endtag%}

          2.1 if標(biāo)簽

          if標(biāo)簽相當(dāng)于python中的if語(yǔ)句,有elifelse相對(duì)應(yīng),可以使用and、or、in、not、==、!=、<=、>=、is、is not,來(lái)進(jìn)行判斷。

          視圖views.py

          def index(request):
              age = random.randint(6, 20)  # 隨機(jī)生成6-20的整數(shù)
          
              context = {
                  'age': age
              }
          
              return render(request, 'index.html', context=context)
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              <p>
                  <span>年齡:<strong>{{ age }}</strong>,</span>
                  <span>適合讀</span>
                  <span>
                      {% if age >= 18 %}
                          【大學(xué)】書(shū)籍
                      {% elif 12 < age and age < 18 %}
                          【高中】書(shū)籍
                      {% else %}
                          【小學(xué)】書(shū)籍
                      {% endif %}
                  </span>
              </p>
          </body>
          </html>
          


          再刷新一次:


          我們還可以使用ifequal/ifnotequal來(lái)比較兩個(gè)值是否相等,如:

          {% ifequal price 0 %}
              <span class="publicimg"><img src="/images/public.png"></span>
          {% else %}
              <span class="publicimg"><img src="/images/vip.png"></span>
          {% endifequal %}
          
          
          

          2.2 for...in...標(biāo)簽

          for標(biāo)簽相當(dāng)于python中的for循環(huán),可以遍歷列表、元組、字符串、字典等一切可以遍歷的對(duì)象。

          # 視圖views.py
          def index(request):
              context = {
                  'articles': [              # 列表
                      '21天學(xué)會(huì)Python',
                      'C++從入門(mén)到入土',
                      'Mysql從入門(mén)到跑路'
                  ],
                  'author': {             # 字典
                      'name': '老P',
                      'age': 18,
                      'sex': 'boy'
                  },
                  'artile_details': [
                      {'title': '21天學(xué)會(huì)Python', 'author': '小P', 'words': 1000},
                      {'title': 'C++從入門(mén)到入土', 'author': '中P', 'words': 2000},
                      {'title': 'Mysql從入門(mén)到跑路', 'author': '老P', 'words': 3000}
                  ]
              }
          
              return render(request, 'index.html', context=context)
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              <ul>
                  {% for article in articles %}
                      <li>{{ article }}</li>
                  {% endfor %}
              </ul>
              <p>獲取字典鍵:</p>
              <ul>
                  {% for key in author.keys %}
                      <li>{{ key }}</li>
                  {% endfor %}
              </ul>
              <p>獲取字典值:</p>
              <ul>
                  {% for value in author.values %}
                      <li>{{ value }}</li>
                  {% endfor %}
              </ul>
              <p>獲取字典鍵值對(duì):</p>
              <ul>
                  {% for key, value in author.items %}
                      <li>{{ key }}:{{ value }}</li>
                  {% endfor %}
              </ul>
          
              <p>文章信息列表:</p>
              <table border="1">
                  <thead>
                      <tr>
                          <th>序號(hào)</th>
                          <th>標(biāo)題</th>
                          <th>作者</th>
                          <th>字?jǐn)?shù)</th>
                      </tr>
                  </thead>
                  <tbody>
                      {% for article_detail in artile_details %}
                          {% if forloop.first %}   <!-- 是否第一次遍歷 -->
                              <tr style="background: red;">
                          {% elif forloop.last %}   <!-- 是否最后一次遍歷 -->
                              <tr style="background: pink;">
                          {% else %}
                              <tr>
                          {% endif %}
                              <td>{{ forloop.counter }}</td>  <!-- 當(dāng)前迭代的次數(shù),下標(biāo)從1開(kāi)始。-->
                              <td>{{ article_detail.title }}</td>
                              <td>{{ article_detail.author }}</td>
                              <td>{{ article_detail.words }}</td>
                          </tr>
                      {% endfor %}
                  </tbody>
              </table>
          
          </body>
          </html>
          
          <!-- 
              forloop.counter:當(dāng)前迭代的次數(shù),下標(biāo)從1開(kāi)始。
              forloop.counter0:當(dāng)前迭代的次數(shù),下標(biāo)從0開(kāi)始。
              forloop.first:返回bool類(lèi)型,如果是第一次迭代,返回true,否則返回false。
              forloop.last:返回bool類(lèi)型,如果是最后一次迭代,返回True,否則返回False。
          
          	forloop.revcounter         反向循環(huán)位置(列表的最后一位是l ,列表第一位是n )
          	forloop.revcounter0        反向循環(huán)位置(列表的最后一位是0 , 列表第一位是n- 1 )
          -->
          


          還有個(gè)for...in...empty,在遍歷的時(shí)候如果需要遍歷的對(duì)象沒(méi)有為空,則執(zhí)行empty下的操作。

              {% for comment in comments %}  
                  {{ comment }}
              {# 在for循環(huán)之前檢查列表大小是常見(jiàn)的,當(dāng)列表為空的時(shí)候給出特別提示,這是常見(jiàn)的,所以for支持可選empry來(lái)當(dāng)為空時(shí)輸出 #}    
              {% empty %}   <!-- comments沒(méi)有或?yàn)榭眨瑒t執(zhí)行empty下的。-->
                  還沒(méi)有評(píng)論~~~
              {% endfor %}
          

          有時(shí)候可能在頁(yè)面上要用上循環(huán)幾次,可以用:

          {% for item in  'x'|ljust:'4' %}  循環(huán)四次
          {%endfor %}
          

          2.3 with標(biāo)簽

          使用一個(gè)簡(jiǎn)單地名字緩存一個(gè)復(fù)雜的變量,當(dāng)你需要使用一個(gè)代價(jià)較大的方法(比如訪問(wèn)數(shù)據(jù)庫(kù))很多次的時(shí)候這是非常有用的。

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              {{ title }}
          
              {% with t1=title %}  <!-- 使用=-->
                  {{ t1 }}
              {% endwith %}
          
              {% with title as t2%} <!-- 使用as 取別名 -->
                  {{ t2 }}
              {% endwith %}
          </body> 
          </html>
          


          注意:定義的變量只能在with語(yǔ)句塊中使用,在with語(yǔ)句塊外面使用取不到這個(gè)變量。

          2.4 url標(biāo)簽

          在模板中,經(jīng)常要寫(xiě)一些超鏈接,比如a標(biāo)簽中需要定義href屬性,當(dāng)然如果通過(guò)硬編碼的方式直接將這個(gè)url寫(xiě)死也是可以,但是不便于以后維護(hù),比如需要修改url地址,那涉及到的地方都要修改,因此建議使用這種反轉(zhuǎn)的方式來(lái)實(shí)現(xiàn),類(lèi)似于django中的reverse一樣。

          # 應(yīng)用urls.py
          from django.urls import path
          from . import views
          
          app_name = 'article'
          urlpatterns = [
              path('index/', views.index, name='index'),
              path('book/', views.book, name='book'),
              path('movie/', views.movie, name='movie'),
              path('city/', views.city, name='city'),
              path('book/hot/<int:book_id>', views.hot_book, name='hot_book')
          ]
          
          # 視圖views.py
          from django.shortcuts import render, HttpResponse
          
          def index(request):
              return render(request, 'index.html')
          
          def book(request):
              return HttpResponse('讀書(shū)頁(yè)面')
          
          def movie(request):
              return HttpResponse('電影頁(yè)面')
          
          def city(request):
              return HttpResponse('同城頁(yè)面')
          
          def hot_book(request, book_id):
              return HttpResponse('最熱門(mén)文章:%d'%book_id)
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
              <style>
                  li{
                      list-style: none;
                      display: inline-block;
                      margin-right: 20px ;
                  }
              </style>
          </head>
          <body>
              <ul>
                  <li><a href="">首頁(yè)</a></li>
                  <li><a href="/article/book/">讀書(shū)</a></li>  <!-- url硬編碼的方式 -->
                  <li><a href="{% url 'article:movie' %}">電影</a></li> <!-- url標(biāo)簽 -->
                  <li><a href="{% url 'article:city' %}">同城</a></li>
                  <li><a href="{% url 'article:hot_book' book_id=1 %}">最火文章</a></li> <!-- url標(biāo)簽 傳遞參數(shù),這個(gè)參數(shù)需要于url映射的參數(shù)名一樣,如果傳遞多個(gè)參數(shù),則空格隔開(kāi) -->
              </ul>
          </body>
          </html>
          


          2.5 autoescape標(biāo)簽

          DTL中默認(rèn)已經(jīng)開(kāi)啟了自動(dòng)轉(zhuǎn)義,會(huì)將哪些特殊字符進(jìn)行轉(zhuǎn)義,比如會(huì)將<轉(zhuǎn)義成<等。

          def index(request):
              comment_info = '個(gè)人博客網(wǎng)站:<a href="http://www.qmpython.com"> 全民python</a>'
              context = {
                  'info': comment_info
              }
              return render(request, 'index.html', context=context)
          

          模板文件:

           <p>個(gè)人博客網(wǎng)站:<a href="http://www.qmpython.com"> 全民python</a></p>
           <p>
                {{ info }}   <!-- DTL默認(rèn)on開(kāi)啟了自動(dòng)轉(zhuǎn)義,轉(zhuǎn)換成普通字符串 -->
           </p>
           <p>
               {% autoescape off %}   <!-- off關(guān)閉自動(dòng)轉(zhuǎn)義,解析html標(biāo)簽 -->
                  {{ info }}
               {% endautoescape %}
           </p>
          


          如果你不知道自己在干什么,最好是使用自動(dòng)轉(zhuǎn)義,這樣網(wǎng)站才不容易出現(xiàn)XSS漏洞(比如有些網(wǎng)站進(jìn)行評(píng)論的時(shí)候,發(fā)一些含惡意的js代碼,如果不進(jìn)行自動(dòng)轉(zhuǎn)義會(huì)進(jìn)行渲染,而不會(huì)做成普通的字符串),比如我個(gè)人博客的評(píng)論就處理了。如果是可信用的,可以關(guān)閉自動(dòng)轉(zhuǎn)義,比如我的文章內(nèi)容是只允許我個(gè)人發(fā)表,是可信任的,所以我直接關(guān)閉。后面可以通過(guò)過(guò)濾器safe類(lèi)似處理。

          2.6 verbatim標(biāo)簽

          默認(rèn)在DTL模板中是會(huì)去解析那些特殊字符的,比如{% %}{{ }}等,如果我們?cè)谀硞€(gè)代碼片段不想使用DTL的解析,那么我們可以將這段代碼放在verbatim標(biāo)簽中。

          # 視圖
          def index(request):
              return render(request, 'index.html')
          
          # 模板
          <body>
              {% if msg %}
                  {{ msg }}
              {% else %}
                  沒(méi)消息
              {% endif %}
              <br>
              {% verbatim %}
                  {% if msg %}
                      {{ msg }}
                  {% endif %}
              {% endverbatim %}
          </body>
          


          這個(gè)主要是用在,有些前端模板語(yǔ)法layui還有vue中也使用{{}}來(lái)表示變量,這些與DTL類(lèi)似,這樣就容易引起混淆,我們可以使用這個(gè)標(biāo)簽,來(lái)屏蔽掉DTL的解析,而讓前端模板去解析。

          2.7 注釋標(biāo)簽

          我們?cè)贖TML中經(jīng)常使用<!-- 注釋內(nèi)容 -->來(lái)進(jìn)行注釋?zhuān)?span style="color: #1E6BB8; --tt-darkmode-color: #1E6BB8;">Django模板中,我們還可以使用其他注釋。

          {# 被注釋的內(nèi)容 #}:將中間的內(nèi)容注釋掉。只能單行注釋。
          {% comment %}被注釋的內(nèi)容{% endcomment %}:可以多行注釋。
          

          這種注釋?zhuān)?dāng)我們查看網(wǎng)頁(yè)元素的時(shí)候是看不到的,即沒(méi)有被渲染,而<!-- -->還是可以看到原樣字符串的。

          2.8 自定義簡(jiǎn)單標(biāo)簽

          1)首先,需要添加一個(gè)templatetags的文件夾, 自定義標(biāo)簽必須處在已經(jīng)安裝了的app(INSTALLED_APPS注冊(cè)了)中的一個(gè)名叫templatetags的包中。

          templatetags 文件夾名字不能修改,這是django規(guī)定的。

          myproject
              |——myproject
               |——__init__.py
               |——asgi.py
               |——settings.py
               |——urls.py
               |——wsgi.py
              |——templates
              |——myapp
               |——migrations
               |——templatetags
                |——__init__.py
                |——custom_tags.py
              |——manage.py
          
          

          2)在templatetags下添加一個(gè)python文件,如我這里創(chuàng)建一個(gè)custom_tags.py文件,在文件中添加對(duì)應(yīng)的自定義標(biāo)簽。

          from django import template
          
          # register的名字是固定的,不可改變
          register = template.Library()
          
          #使用裝飾器注冊(cè)自定義標(biāo)簽  
          @register.simple_tag
          def curr_date(args):#args可傳參數(shù),根據(jù)實(shí)際需求而定
              return datetime.datetime.now().strftime(args)
          

          3)在要使用自定義標(biāo)簽的HTML模板中導(dǎo)入和使用自定義標(biāo)簽文件:

          {# 加載自定義標(biāo)簽所在的文件名,由于templatetags的文件名是固定的,django可以直接找到過(guò)自定義標(biāo)簽文件所在的位置 #}
          {% load custom_tags %}
          
          <h3>自定義標(biāo)簽</h3>
          時(shí)間日期:{% curr_date "%Y-%m-%d"%}
          

          我們?cè)賮?lái)定義簡(jiǎn)單標(biāo)簽article/templatetags/menu_tags.py

          from django import template
          
          # register的名字是固定的,不可改變
          register = template.Library()
          @register.simple_tag
          def my_menu():
              menu_list = ['首頁(yè)','項(xiàng)目實(shí)戰(zhàn)','每日一練']  
            
              return menu_list
          
          

          模板文件templates/article/my_menu.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>自定義簡(jiǎn)單標(biāo)簽</title>
          </head>
          <body>
          <h1>-----------菜單欄--------------</h1>
          <br/>
          {% load menu_tags %}	<!-- 導(dǎo)入自定義的標(biāo)簽文件 -->
          
          {% my_menu as menus %}  <!-- 注意:這里需要使用as將標(biāo)簽文件返回的值賦給一個(gè)變量,然后再引用!!!-->
          
          <ul>
              {% for menu in menus %}  {# 企圖使用 {% for menu in my_menu %} 是沒(méi)效果的 #}
                  <li>{{menu}}</li>
              {% endfor %}
          </ul> 
          
          </body>
          </html>
          

          視圖渲染views.py

          def test(request):
              return render(request, 'article/my_menu.html')
          


          2.9 自定義包含標(biāo)簽inclusion_tag

          一種比較普遍的tag類(lèi)型只是渲染其他模塊顯示下的內(nèi)容,這樣的類(lèi)型叫做inclusion_tag,常用的模板標(biāo)簽是通過(guò)渲染其他模板顯示數(shù)據(jù)的。

          inclusion_tag作用:創(chuàng)建一個(gè)動(dòng)態(tài)頁(yè)面文件a.html,這個(gè)頁(yè)面可以在另外一個(gè)頁(yè)面b.html中被調(diào)用,實(shí)現(xiàn)這個(gè)頁(yè)面a中有的功能。

          例如,上面一個(gè)導(dǎo)航頁(yè)面my_menu.html,基本在每個(gè)頁(yè)面中都要包含導(dǎo)航,如我的個(gè)人博客一樣:



          那要怎么樣呢?

          例如,我們?cè)谑醉?yè)模板中,先試下用include來(lái)引入導(dǎo)航模板看看(include這個(gè)后面具體學(xué)習(xí),這里只演示作用)。

          與上面自定義簡(jiǎn)單標(biāo)簽類(lèi)似,在自定義標(biāo)簽文件里面自定義包含標(biāo)簽:

          from django import template
          
          from article.models import Column
          
          # register的名字是固定的,不可改變
          register = template.Library()
          #使用裝飾器注冊(cè)自定義包含標(biāo)簽
          @register.inclusion_tag('article/my_menu.html') #將返回值傳給my_menu.html去,可以定義name,否則使用函數(shù)名
          def my_menu():
              # menus = ['首頁(yè)','項(xiàng)目實(shí)戰(zhàn)','每日一練']
              menus = Column.objects.all()
              
              return {'menus':menus}  
          
          

          my_menu.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>自定義包含標(biāo)簽</title>
          </head>
          <body>
          <ul>
              {% for menu in menus %}
                <li> {{menu}} </li>
              {% endfor %}
          </ul>
          </body>
          </html>
          

          調(diào)用的html頁(yè)面文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>首頁(yè)</title>
          </head>
          <body>
          
          {% load menu_tags %}   <!-- 必須要先加載創(chuàng)建標(biāo)簽的文件-->
          
          {% my_menu %}    <!-- 調(diào)用my_menu.html頁(yè)面文件,這里使用該標(biāo)簽的函數(shù)名來(lái)調(diào)用-->
          
          <h1>首頁(yè)</h1>
          
          </body>
          </html>
          

          視圖渲染:

          def test(request):
          
              return render(request, 'article/index.html')
          

          2.10 人性化語(yǔ)義標(biāo)簽

          除了上述功能性標(biāo)簽外, Django 還提供了很多輔助性標(biāo)簽,這些標(biāo)簽只是為了使變量輸 出變得更加可讀,下面對(duì)這些標(biāo)簽進(jìn)行簡(jiǎn)單介紹。首先為了使用這些標(biāo)簽,需要在INSTALLED_APPS 中注冊(cè)django .contrib.humanize, 然后在模板中引用humanize:{% raw %}{% load humanize % }{% endraw %}

          apnumber

          將數(shù)字1 ~ 9 轉(zhuǎn)換為英文單詞,但是其他數(shù)字不轉(zhuǎn)換,如數(shù)字10 將被原樣輸出。示例:

          數(shù)字1 被轉(zhuǎn)換為one ;
          數(shù)字2 被轉(zhuǎn)換為two ;
          數(shù)字10 仍顯示10 ;
          

          如果當(dāng)前工程語(yǔ)言是中文的話,數(shù)字將會(huì)被轉(zhuǎn)換為對(duì)應(yīng)的漢字,例如:

          {% raw %}
          {{ 1|apnumber }}
          {{ 2|apnumber }}
          {{ 5|apnurnber }}
          {% endraw %}
          

          如果當(dāng)前工程語(yǔ)言是中文的話,數(shù)字將會(huì)被轉(zhuǎn)換為對(duì)應(yīng)的漢字,例如:

          輸出:

          一
          二
          五
          

          intcomma

          輸出以逗號(hào)分隔的數(shù)字,如4500 輸出4,500, 4500.2 輸出4,500.2 。

          intword

          以文字形式輸出數(shù)字,如1000000 輸出“ 1.0 million ”, 1200000 輸出“ 1,2 Million ” 。對(duì)于中文系統(tǒng),將會(huì)輸出對(duì)應(yīng)的中文,如1200000 輸出" 1.2 百萬(wàn)” 。

          naturalday

          將當(dāng)前日期以及前后一天輸出為today 、yesterday 和tomorrow ,而中文系統(tǒng)分別輸出 “今天”“昨天”和“明天” 。

          naturaltime

          對(duì)于日期時(shí)間格式,時(shí)間值與系統(tǒng)當(dāng)前時(shí)間比較,然后輸出結(jié)果。如當(dāng)前時(shí)間輸出 “ now ”, 29 秒前輸出“ 29 sec onds ago ” 。如果使用naturaltime 輸出今天、昨天、明天的話, 就會(huì)變成“現(xiàn)在”“ 23 小時(shí)·以后”“ 1 日之前” 。

          ordinal

          將數(shù)字轉(zhuǎn)換為序數(shù),如l 輸出“ 1 st ”;2 輸出“ 2nd ”;3 輸出“ 3rd ” 。注意此時(shí)中文與 英文的輸出一樣。

          3. 模板過(guò)濾器

          在模板中,有時(shí)候需要對(duì)一些數(shù)據(jù)進(jìn)行處理以后才能使用,一般在Python中我們是通過(guò)函數(shù)的形式來(lái)完成的,因?yàn)樵?span style="color: #1E6BB8; --tt-darkmode-color: #1E6BB8;">DTL中,不支持函數(shù)的調(diào)用形式(),因此在模板中,則是通過(guò)過(guò)濾器來(lái)實(shí)現(xiàn)的,過(guò)濾器使用的是|來(lái)使用。語(yǔ)法:

          {{ 變量名|過(guò)濾器名:傳給過(guò)濾器的參數(shù)}}
          

          3.1 常用過(guò)濾器

          比如使用date過(guò)濾器。

          # 視圖
          from datetime import datetime
          
          def index(request):
              now_time = datetime.now()
              context = {
                  'now_time': now_time
              }
              return render(request, 'index.html', context=context)
          
          
          # 模板文件
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              {{ now_time }} <!-- 原始渲染 -->
              <br>
              {{ now_time | date:'Y-m-d H:i:s' }}  <!-- 通過(guò)過(guò)濾器,先將日期格式化,再渲染出-->
          </body>
          </html>
          


          date時(shí)間過(guò)濾器格式:

          格式字符描述示例Y4位數(shù)的年1999y2位數(shù)的年99m2位數(shù)的月01,09n1位數(shù)的月1,9,12d2位數(shù)的日01,09,31j1位數(shù)的日1,9,31g12小時(shí)制的一位數(shù)的小時(shí)1,9,12G24小時(shí)制的一位數(shù)小時(shí)0,8,23h12小時(shí)制的兩位數(shù)的小時(shí)01,09,12H24小時(shí)制的兩位數(shù)的小時(shí)01,13,24i分鐘00-59s秒00-59

          django常用過(guò)濾器:

          add:字符串相加,數(shù)字相加,列表相加,如果失敗,將會(huì)返回一個(gè)空字符串。default:提供一個(gè)默認(rèn)值,在這個(gè)值被django認(rèn)為是False的時(shí)候使用。比如:空字符串、None、[]、{}等。區(qū)別于default_if_none,這個(gè)只有在變量為None的時(shí)候才使用默認(rèn)值。first:返回列表中的第一個(gè)值。last:返回列表中的最后一個(gè)值。date:格式化日期和時(shí)間。time:格式化時(shí)間。join:跟python中的join一樣的用法。length:返回字符串或者是數(shù)組的長(zhǎng)度。length_is:字符串或者是數(shù)組的長(zhǎng)度是否是指定的值。lower:把所有字符串都編程小寫(xiě)。truncatechars:根據(jù)后面給的參數(shù),截?cái)嘧址绻^(guò)了用表示。{{value|truncatechars:5}},如果value是等于北京歡迎您,那么輸出的結(jié)果是北京...,為啥不是北京歡迎您...呢?因?yàn)槿齻€(gè)點(diǎn)也占了三個(gè)字符,所以北京 + 三個(gè)點(diǎn)的字符長(zhǎng)度就是5。truncatewords:類(lèi)似truncatechars,不過(guò)不會(huì)切割html標(biāo)簽,{{value|truncatewords:5}},如果value是等于<p>北京歡迎您</p>,那么輸出的結(jié)果是<p>北京...</p>capfirst:首字母大寫(xiě)。slice:切割列表。用法跟python中的切片操作是一樣的,區(qū)間是前閉合后開(kāi)放。striptags:去掉所有的html標(biāo)簽。safe:關(guān)閉變量的自動(dòng)轉(zhuǎn)義,解析html標(biāo)簽。floatformat:浮點(diǎn)數(shù)格式化。更多可以查詢(xún)官方文檔:https://yiyibooks.cn/xx/Django_1.11.6/ref/templates/builtins.html英文:https://docs.djangoproject.com/en/1.11/ref/templates/builtins/

          過(guò)濾器總結(jié):1、作用:對(duì)變量進(jìn)行過(guò)濾。在真正渲染出來(lái)之前,過(guò)濾器會(huì)根據(jù)功能處理好變量,然后得出結(jié)果后再替換掉原來(lái)的變量展示出來(lái)。2、語(yǔ)法:{{greeting|lower}},變量和過(guò)濾器中間使用管道符號(hào)”|”進(jìn)行使用。3、可以通過(guò)管道符號(hào)進(jìn)行鏈?zhǔn)秸{(diào)用,比如實(shí)現(xiàn)一個(gè)功能,先把所有字符變成小寫(xiě),把第一個(gè)字符轉(zhuǎn)換成大寫(xiě),如{{message|lower|capfirst}}

          4、過(guò)濾器可以使用參數(shù),在過(guò)濾器名稱(chēng)后面使用冒號(hào)”:”再加上參數(shù),比如要把一個(gè)字符串中所有的空格去掉,則可以使用cut過(guò)濾器,代碼如下{{message|cut:" "}},冒號(hào)和參數(shù)之間不能有任何空格,一定要緊挨著。

          3.2 自定義過(guò)濾器

          雖然DTL給我們內(nèi)置了許多好用的過(guò)濾器,但是有些時(shí)候還是不能滿足我們的需求,因此Django給我們提供了一個(gè)接口,可以讓我們自定義過(guò)濾器,實(shí)現(xiàn)自己的需求。

          步驟:

          1、首先在某個(gè)應(yīng)用app中,創(chuàng)建一個(gè)python包,叫做templatetags,注意名字不能改動(dòng),不然找不到。

          2、在這個(gè)templatetags包下創(chuàng)建一個(gè)python文件用來(lái)存儲(chǔ)過(guò)濾器。

          3、在新建的python文件中,定義過(guò)濾器(也就是函數(shù)),這個(gè)函數(shù)的第一個(gè)參數(shù)永遠(yuǎn)是被過(guò)濾器的那個(gè)值,并且如果在使用過(guò)濾器的時(shí)候傳遞參數(shù),那么還可以定義另外一個(gè)參數(shù),但是過(guò)濾器最多只能有2個(gè)參數(shù)。

          4、自定義完過(guò)濾器,要使用django.template.Library.filter進(jìn)行注冊(cè)。

          5、過(guò)濾器所在app所在app需要在settings.py中進(jìn)行注冊(cè)。

          6、在模板中使用load標(biāo)簽加載過(guò)濾器所在的python包。

          7、在模板中使用自定義的過(guò)濾器。

          我們來(lái)實(shí)現(xiàn)一個(gè)朋友圈,或者文章發(fā)表時(shí)間顯示的過(guò)濾器:

          # 自定義過(guò)濾器 date_filter.py
          from django import template
          
          from datetime import datetime, timedelta
          
          # 將注冊(cè)類(lèi)實(shí)例化為register對(duì)象
          # register=template.Library() 創(chuàng)建一個(gè)全局register變量,它是用來(lái)注冊(cè)你自定義標(biāo)簽和過(guò)濾器的,只有向系統(tǒng)注冊(cè)過(guò)的tags,系統(tǒng)才認(rèn)得你。
          # register 不能做任何修改,一旦修改,該包就無(wú)法引用
          register = template.Library()
          
          # 使用裝飾器注冊(cè)自定義過(guò)濾器
          @register.filter
          def date_filter(value):
              # 判斷一下,是不是時(shí)間日期類(lèi)型
              if not isinstance(value, datetime):
                  return value
          
              now = datetime.now() + timedelta(hours=8)  # 將UTC時(shí)間轉(zhuǎn)為本地時(shí)間
          
              # total_seconds()是獲取兩個(gè)時(shí)間之間的總差
              timestamp = (now - value).total_seconds()
          
              if timestamp < 60:
                  return '剛剛'
              elif 60 <= timestamp < 60*60:   # sec >= 60 and sec < 60*60
                  mint = int(timestamp / 60)
                  return '{}分鐘前'.format(mint)
              elif 60*60 <= timestamp < 60*60*24:
                  hour = int(timestamp / 60 / 60)
                  return '{}小時(shí)前'.format(hour)
              elif 60*60*24 <= timestamp < 60*60*24*2:
                  return '昨天'
              else:
                  return timestamp.strftime('%Y-%m-%d %H:%M:%S')
          
          
          # 視圖views.py
          from django.shortcuts import render, HttpResponse
          
          from datetime import datetime
          
          def index(request):
              context = {
                  'public_time': datetime(year=2020, month=3, day=23, hour=23, minute=0, second=0)
              }
              print(context)
              return render(request, 'index.html', context=context)
          
          
          
          # 模板文件
          {% load date_filter %}
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              {{ public_time|date_filter }}
          
          </body>
          </html>
          


          4. 模板結(jié)構(gòu)化優(yōu)化

          4.1 引入模板

          有時(shí)候一些代碼是在許多模板中都用到的,如果每次都重復(fù)的去拷貝代碼那肯定不符合項(xiàng)目的規(guī)范,一般我們可以把這些重復(fù)性的代碼抽取出來(lái),就類(lèi)似于Python的函數(shù)一樣,以后想要使用這些代碼的時(shí)候,就通過(guò)include包含進(jìn)來(lái),這個(gè)標(biāo)簽就是include。比如大多數(shù)網(wǎng)頁(yè)都有頂部,中間,底部,可能進(jìn)入任何頁(yè)面頂部和底部都是一樣的,只有中間部分內(nèi)容不同,這個(gè)時(shí)候頂部和底部,我們就可以通過(guò)include包含起來(lái)。


          # 頂部,header.html
          <header>
              <ul>
                  <li>首頁(yè)</li>
                  <li>Python教程</li>
                  <li>Python Web開(kāi)發(fā)</li>
                  <li>Python爬蟲(chóng)</li>
              </ul>
              <p>用戶名:{{ username }}</p> <!-- 用于測(cè)試是否傳參 -->
          </header>
          
          # 底部,footer.html
          <footer>
              <div>?2019<a href="/">全民python</a> | 
                  <a href="http://beian.miit.gov.cn" rel="nofollow">粵ICP備18143893號(hào)</a> | 
              </div>
          </footer>
          
          # 首頁(yè),index.html
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
              <style>
                  div{
                      margin: 10px;
                  }
              </style>
          </head>
          <body>
            {% include 'header.html' with username='全民python' %}  <!-- 引入模板,并用with傳遞參數(shù) -->
            <div>
              這是中間內(nèi)容
            </div>
            {% include 'footer.html' %}
          </body>
          </html>
          

          視圖:

          def index(request):
              return render(request, 'index.html')
          


          我們使用include標(biāo)簽時(shí),如果引入的html代碼中需要傳入變量,則需要在所引入的view視圖中獲取變量,如果引入的html代碼中的變量是一個(gè)公共變量,則需要重復(fù)獲取N次,使用自定義包含標(biāo)簽inclusion_tag,可以在定義文件中獲取一次即可。

          templates/article/my_menu.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>自定義簡(jiǎn)單標(biāo)簽</title>
          </head>
          <body>
          <h1>-----------菜單欄--------------</h1>
          <br/>
          {% load menu_tags %}	<!-- 導(dǎo)入自定義的標(biāo)簽文件 -->
          
          {% my_menu as menus %}  <!-- 注意:這里需要使用as將標(biāo)簽文件返回的值賦給一個(gè)變量,然后再引用!!!-->
          
          <ul> 
              {% for menu in menus %} {# 企圖使用 {% for menu in my_menu %} 是沒(méi)效果的 #}
                  <li>{{menu}}</li>
              {% endfor %}
          </ul> 
          
          </body>
          </html>
          

          article/templatetags/menu_tags.py

          from django import template
          from article.models import Column
          
          # register的名字是固定的,不可改變
          register = template.Library()
          @register.simple_tag
          def my_menu():
              #menu_list = ['首頁(yè)','項(xiàng)目實(shí)戰(zhàn)','每日一練']  
              menu_list = Column.objects.all()
            
              return menu_list
          

          templates/article/index.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>首頁(yè)</title>
          </head>
          <body>
          
          {% include 'article/my_menu.html' %}
          
          <h1>首頁(yè)</h1>
          
          </body>
          </html>
          


          兩者感覺(jué)效果一樣。

          4.2 模板繼承

          對(duì)于模板的重復(fù)利用,除了使用include標(biāo)簽引入,還有另外種方式來(lái)實(shí)現(xiàn),那就是模板繼承。模板繼承類(lèi)似于Python中的類(lèi),在父類(lèi)中可以先定義好一些變量和方法,然后在子類(lèi)中實(shí)現(xiàn),模板繼承也可以在父模板中先定義好一些子模板需要用到的代碼,然后子模板直接繼承就可以了,并且因?yàn)樽幽0蹇隙ㄓ凶约旱牟煌a,因此可以在父模板中定義一個(gè)block接口,然后子模板再去實(shí)現(xiàn)。

          我們將上面那個(gè)例子,使用模板繼承改寫(xiě)下,將固定不變的頂部和底部,放在父模板中,中間變動(dòng)的部分,子模板去實(shí)現(xiàn)。

          <!-- 父模板-->
          
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>{% block title %}全民python{% endblock %}</title>
              <style>
                  *{
                      margin: 0;
                      padding: 0;
                  }
                  header,footer{
                      background: black;
                      height: 60px;
                      width: 100%;
                      color: white;
                      text-align: center;
                      line-height: 40px;
                  }
                  footer{
                      height: 90px;
                      line-height: 90px;
                      position: absolute;
                      bottom: 0;
                  }
                  ul li{
                      list-style: none;
                      float: left;
                      margin: 20px;
                  }
                  #loginbox{
                      width: 400px;
                      height: 200px;
                      border: 1px solid red;
                      margin: 90px auto;
                      text-align: center;
                  }
              </style>
          </head>
          <body>
              <header>
                 <ul>
                     <li>首頁(yè)</li>
                     <li>編程語(yǔ)言</li>
                     <li>項(xiàng)目實(shí)戰(zhàn)</li>
                     <li>每日一學(xué)</li>
                  </ul>
              </header>
              <div class="content">
                  {% block content %}
                      這是子模板自己實(shí)現(xiàn)的部分
                  {% endblock %}
              </div>
              <footer >
                  這是footer部分
              </footer>
          </body>
          </html>
          
          
          <!-- 子模板-->
          {% extends 'base.html' %}  <!-- extends必須是模板中的第一個(gè)出現(xiàn)的標(biāo)簽 -->
          {% block title %}{{ block.super }}-登錄界面{% endblock %} <!-- block.super繼承父類(lèi)的內(nèi)容,否則會(huì)覆蓋父類(lèi)內(nèi)容 -->
          {% block content %}
              <div id="loginbox">
                  <br/>
                  <h2>登錄界面</h2>
                  <br/>
                  <form>
                      帳 號(hào):<input type="text">
                      <br/>
                      <br/>
                      密 碼:<input type="password">
                      <br/>
                      <br/>
                      <input type="submit" value="登錄">
                          
                      <input type="button" value="注冊(cè)">
                  </form>
              </div>
          {% endblock %}
          

          視圖函數(shù):

          def index(request):
              return render(request, 'index.html')
          

          效果展示:


          總結(jié):

          1. 模板繼承使用extends標(biāo)簽實(shí)現(xiàn),通過(guò)使用block來(lái)給子模板開(kāi)放接口;
          2. extends必須是模板中第一個(gè)出現(xiàn)的標(biāo)簽;
          3. 子模板中的內(nèi)容必須放在父模板定義好的block中,否則將不會(huì)被渲染;
          4. 如果在某個(gè)block中需要使用父模板的內(nèi)容,那么可以使用{{ block.super }}來(lái)繼承;
          5. 子模板決定替換的block塊,無(wú)須關(guān)注其它部分,沒(méi)有定義的塊即不替換,直接使用父模板的block塊;
          6. 除了在開(kāi)始的地方定義名字,我們還可以在結(jié)束的時(shí)候定義名字,如{% block title %}{% endblock %},這樣在大型模板中顯得尤其有用,能讓我們快速看到block所包含的開(kāi)始和結(jié)束。

          模板引入與自定義inclusion_tag的區(qū)別:模板導(dǎo)入的頁(yè)面內(nèi)容是靜態(tài)的、不變的,而通過(guò)自定義inclusion_tag導(dǎo)入的頁(yè)面文件可以是動(dòng)態(tài)的,可動(dòng)性自己掌控。

          5. 加載靜態(tài)文件

          在一個(gè)網(wǎng)頁(yè)中,不僅僅只有一個(gè)html,還需要css樣式,js腳本以及一些圖片,因此在DTL中加載靜態(tài)文件是一個(gè)必須要解決的問(wèn)題,在DTL中,使用static標(biāo)簽來(lái)加載靜態(tài)文件,要使用static標(biāo)簽,首先需要{% load static %}

          1、首先,settings.py文件中,確保django.contrib.staticfiles已經(jīng)添加到INSTALLED_APPS中。

          INSTALLED_APPS = [
              ...
              'django.contrib.staticfiles',
              ...
          ]
          

          2、設(shè)置DEBUG調(diào)試模式。

          # 在settings.py中,默認(rèn)值是DEBUG = True
          DEBUG = True
          

          當(dāng)我們?cè)陂_(kāi)發(fā)django應(yīng)用時(shí)如果設(shè)置了 DEBUG=True,那么django便會(huì)自動(dòng)幫我們對(duì)靜態(tài)文件進(jìn)行路由;但是當(dāng)我們?cè)O(shè)置DEBUG=False后,靜態(tài)文件找不到了,「img、css、js」都提示404,無(wú)法準(zhǔn)確的訪問(wèn) static 靜態(tài)文件。

          3、在開(kāi)發(fā)模式下(Debug=True)時(shí),訪問(wèn)靜態(tài)文件有下面兩種情況:1)在已注冊(cè)的應(yīng)用app下創(chuàng)建一個(gè)靜態(tài)文件夾名稱(chēng)static,然后再再這個(gè)static目錄下創(chuàng)建于app同名的 文件夾用于存放靜態(tài)文件(避免不同應(yīng)用app,靜態(tài)文件名字一樣,造成沖突)。

          Django將通過(guò) django.contrib.staticfiles在每個(gè)appstatic文件夾中為我們自動(dòng)查找這些靜態(tài)文件。

          2)如果有些靜態(tài)文件和應(yīng)用沒(méi)什么太大的關(guān)系,我們可以在項(xiàng)目根目錄下再創(chuàng)建static目錄,這個(gè)時(shí)候我們還需要在settings.py文件配置添加STATICFILES_DIRS,以后DTL就會(huì)在這個(gè)列表的路徑中查找靜態(tài)文件。

          # django2.x方式
          # STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]  # 這里指靜態(tài)文件保存哪個(gè)目錄下,這個(gè)“static”指目錄名
          
          # django3.x方式
          # 一般用來(lái)設(shè)置通用的靜態(tài)資源,對(duì)應(yīng)的目錄不放在APP下,而是放在Project下,例如:
          STATICFILES_DIRS = [BASE_DIR / 'static']
          
          

          然后再像上面一樣加載靜態(tài)文件使用,一般直接在根項(xiàng)目下新建static,然后在下面新建不同以應(yīng)用名稱(chēng)命名的目錄。

          STATICFILES_DIRS告訴django,首先到STATICFILES_DIRS里面尋找靜態(tài)文件,其次再到各個(gè)appstatic文件夾里面找(注意,django查找靜態(tài)文件是惰性查找,查找到第一個(gè),就停止查找了)。

          4、只有在生產(chǎn)模式(Debug=False)時(shí),STATIC_ROOT設(shè)置才生效。

          STATIC_ROOT 是在部署靜態(tài)文件時(shí)(pyhton manage.py collectstatic)所有的靜態(tài)文靜聚合的目錄,STATIC_ROOT要寫(xiě)成絕對(duì)地址,如下例子STATIC_ROOT設(shè)為根目錄下的static_new文件,而STATICFILES_DIRS使用根目錄下的static目錄。

          #STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]  # 這里指靜態(tài)文件保存哪個(gè)路徑,這個(gè)“static”指目錄名
          STATICFILES_DIRS = [BASE_DIR / 'static']
          
          if not DEBUG:
              #STATIC_ROOT = os.path.join(BASE_DIR, "static_new") #使用 collectstatic后收集的靜態(tài)文件的存放絕對(duì)路徑
              STATIC_ROOT = [BASE_DIR / 'static_new']
          

          當(dāng)部署項(xiàng)目時(shí),在終端輸入:

          # django會(huì)把所有的static文件都復(fù)制到STATIC_ROOT文件夾下
          python manage.py collectstatic
          


          然后可以看到根目錄下有創(chuàng)建了一個(gè)static_new文件夾,里面有STATICFILES_DIRS里設(shè)置的文件夾里的靜態(tài)文件,同時(shí)也有各appstatic文件夾里的靜態(tài)文件。

          在部署模式(Debug=False)時(shí),Django會(huì)從STATIC_ROOT設(shè)置的文件夾讀取靜態(tài)文件,而不再?gòu)?span style="color: #1E6BB8; --tt-darkmode-color: #1E6BB8;">STATICFILES_DIRS設(shè)置的文件夾或app下的static文件夾。所以在(Debug=False)時(shí)需要先python manage.py collectstatic同步一下靜態(tài)文件。

          說(shuō)明:真實(shí)上生產(chǎn),靜態(tài)文件可能就交給nginx了,配置好即可,就不會(huì)再?gòu)膁jango里面讀取靜態(tài)文件了。具體后續(xù)我們會(huì)細(xì)說(shuō)

          5、上面我們已經(jīng)配置好靜態(tài)文件了,那怎么樣訪問(wèn)呢?

          如果在瀏覽器是訪問(wèn),不可能輸入你的靜態(tài)文件的本地絕對(duì)地址吧,比如我的一種圖片的本地地址為 /root/src/project/QmpythonBlog/static/image/article/article_cover.png,那我們不可能

          在瀏覽器上直接輸入:http://127.0.0.1:5044/root/src/project/QmpythonBlog/static/image/article/article_cover.png 這樣子,瀏覽器會(huì)報(bào)錯(cuò), 沒(méi)有該頁(yè)面,那么django是如何讓瀏覽器也可以訪問(wèn)服務(wù)器上的靜態(tài)文件呢?

          上面已經(jīng)說(shuō)了,直接訪問(wèn)服務(wù)器本地的地址是不行的,那就需要一個(gè)映射。

          django利用STATIC_URL來(lái)讓瀏覽器可以直接訪問(wèn)靜態(tài)文件。

          settings.py文件中確保配置了STATIC_URLSTATIC_URL用于引用STATICFILES_DIRSSTATIC_ROOT所指向的靜態(tài)文件。

          當(dāng)我們創(chuàng)建Django項(xiàng)目的時(shí)候,在setting.py中默認(rèn)就已經(jīng)設(shè)置了。

          # 靜態(tài)文件存儲(chǔ),一般是我們的JS、css、系統(tǒng)的圖片文件等。
          # 這個(gè)“static”指訪問(wèn)靜態(tài)文件,引入時(shí)用的別名
          # 通過(guò)http://127.0.0.1/static/***就可以訪問(wèn)相關(guān)的靜態(tài)文件了。
          
          STATIC_URL = '/static/'
          

          例如:在應(yīng)用user下新建static目錄,再在static下新建user目錄:


          視圖:

          # user應(yīng)用下的視圖views.py
          
          def index(request):
              return render(request, 'user/index.html')
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>用戶登錄首頁(yè)</title>
          </head>
          <body>
              <p>用戶界面</p>
              <img src="/static/user/img/logo.png">  <!-- 如果配置文件是 STATIC_URL='/abc/',則這里url:/abc/user/img/logo.png-->
          </body>
          </html>
          

          但是上面要寫(xiě)絕對(duì)路徑不方便,那我們可以通過(guò)static標(biāo)簽來(lái)加載靜態(tài)文件:

          {% load static %}
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>用戶登錄首頁(yè)</title>
          </head>
          <body>
              <p>用戶界面</p>
          {#    <img src="/static/user/img/logo.png">#}
          
              <img src="{% static '/user/img/logo.png' %}"> <!-- 通過(guò)static標(biāo)簽,django會(huì)去static目錄下尋找 -->
          </body>
          </html>
          

          {% static %}這個(gè)模板變量使用的就是STATIC_URL的值,例如默認(rèn)的STATIC_URL值為/static/,那么上面模板變量引用后的值便為/static/開(kāi)頭的地址。

          那么STATIC_URL又是怎么能正確的找到靜態(tài)文件地址的呢。

          1)在開(kāi)發(fā)模式下(Debug=True)時(shí),使用的是STATICFILES_DIRSapp下的static中的靜態(tài)文件,Django有默認(rèn)的對(duì)STATIC_URL路由能自動(dòng)找到放在里面的靜態(tài)文件。

          2)在部署模式(Debug=False)時(shí),使用的是STATIC_ROOT中的靜態(tài)文件,此時(shí)則沒(méi)有了默認(rèn)的對(duì)STATIC_URL的路由,需要自己在projecturls.py中寫(xiě)一個(gè),將STATIC_URL開(kāi)頭的請(qǐng)求轉(zhuǎn)發(fā)到STATIC_ROOT中進(jìn)行查找。

          from django.views.static import serve
          from django.conf.urls.static import static
          urlpatterns = [
              re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}, name='static'),
          ]
          

          在部署生產(chǎn)環(huán)境時(shí)(Debug=False),通常使用另外一種方法就是使用Nginx來(lái)實(shí)現(xiàn)。

          如果你在項(xiàng)目中用到了static這個(gè)模板標(biāo)簽,那一定要將nginx(或其他)服務(wù)器的/static配置到與STATIC_ROOT一致!(如果執(zhí)行了收集的話)

          可以參考django部署配置:Centos7中使用Nginx+uWSGI+Django部署Web項(xiàng)目

          此時(shí)我們?cè)趹?yīng)用中加載靜態(tài)文件的話就只需要這么來(lái)寫(xiě)了,需要將STATIC_URL設(shè)為/static/,以img加載為例:

          <img src="/static/images/good.png" alt="My image"/>
          

          額外知識(shí)點(diǎn):

          1、如果不想在模板文件中每次都通過(guò){% load static %}加載靜態(tài)文件。

          TEMPLATES = [
              {
                  'BACKEND': 'django.template.backends.django.DjangoTemplates',
                  #'DIRS': [os.path.join(BASE_DIR, 'templates')]  # django2寫(xiě)法
                   'DIRS': [BASE_DIR / 'templates'],  # django3寫(xiě)法
                  ,
                  'APP_DIRS': True,
                  'OPTIONS': {
                      'context_processors': [
                          'django.template.context_processors.debug',
                          'django.template.context_processors.request',
                          'django.contrib.auth.context_processors.auth',
                          'django.contrib.messages.context_processors.messages',
                      ],
                      'builtins': ['django.templatetags.static']  # 添加這一行,就會(huì)將static當(dāng)作內(nèi)置的標(biāo)簽,無(wú)需再手動(dòng)load
                  },
              },
          ]
          

          備注:一般個(gè)人傾向于,直接將static文件放到項(xiàng)目根目錄下,下面再根據(jù)app名字進(jìn)行分門(mén)別類(lèi)。



          #Django#

          伙伴們大家好,本期想給大家分享一個(gè)模板,就是基于HTML+CSS+JS來(lái)模仿京東商城的前端界面。感興趣的小伙伴可以轉(zhuǎn)發(fā)該文,私信小編獲取代碼。

          先看一下主界面的展示效果圖,為gif動(dòng)態(tài)圖,可點(diǎn)擊查看。

          主要技術(shù)點(diǎn)

          1、主界面采用平滑的輪播圖動(dòng)態(tài)展示商品,左側(cè)采用側(cè)邊導(dǎo)航欄+多個(gè)浮動(dòng)DIV展示商品具體信息,上方為導(dǎo)航欄,右側(cè)用浮動(dòng)DIV完成公告欄的設(shè)計(jì)。

          2、除了正常看到的界面,在登陸和注冊(cè)界面中,使用juery完成數(shù)據(jù)的驗(yàn)證和友好的樣式展示。

          3、此商城模板主要包括主界面、登陸界面、注冊(cè)界面、客戶問(wèn)題反饋界面。

          主界面

          登陸界面

          注冊(cè)界面

          客戶反饋界面

          商品詳情界面

          最后上一下代碼圖,感興趣的小伙伴可以轉(zhuǎn)發(fā)+私信小編獲取代碼。同時(shí)歡迎持續(xù)關(guān)注小編相互交流。

          介紹:

          art-template 是一個(gè)簡(jiǎn)約、超快的模板引擎。 它采用作用域預(yù)聲明的技術(shù)來(lái)優(yōu)化模板渲染速度,從而獲得接近 JavaScript 極限的運(yùn)行性能,并且同時(shí)支持 NodeJS 和瀏覽器。

          1.1 模板語(yǔ)法:

          art-template 同時(shí)支持兩種模板語(yǔ)法。標(biāo)準(zhǔn)語(yǔ)法可以讓模板更容易讀寫(xiě);原始語(yǔ)法具有強(qiáng)大的邏輯處理能力。

          標(biāo)準(zhǔn)語(yǔ)法

          {{if user}}
          <h2>{{user.name}}</h2>
          {{/if}}
          

          原始語(yǔ)法

          <% if (user) { %>
          <h2><%=user.name %></h2>
          <% } %>
          

          1.2 核心方法:

          // 基于模板名渲染模板
          template(filename, data);
          
          // 將模板源代碼編譯成函數(shù)
          template.compile(source, options);
          
          // 將模板源代碼編譯成函數(shù)并立即執(zhí)行
          template.render(source, data, options);
          

          2 安裝

          2.1 安裝方法:

          • 通過(guò)npm安裝: npm install art-template --save
          • 下載安裝

          2.2 在瀏覽器中編譯

          因?yàn)闉g覽器不支持文件系統(tǒng),所以 template(filename, data) 不支持傳入文件路徑,它內(nèi)部使用 document.getElementById(filename).innerHTML 來(lái)獲取模板,例如:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <meta http-equiv="X-UA-Compatible" content="ie=edge">
              <title>Document</title>
              <!-- 引入template-web.js -->
              <script src="./node_modules/art-template/lib/template-web.js"></script>
          </head>
          <body>
              <div id="container"></div>
              <!-- 創(chuàng)建 script 標(biāo)簽創(chuàng)建模板,注意下面幾點(diǎn) -->
              <!-- 1. type="text/該斜杠后可以是 html,template... 不是script即可)" -->
              <!-- 2. 給 script 標(biāo)簽添加 id ,此 id 即為模板 id -->
              <!-- 3.模板 script 標(biāo)簽必須在 template() 方法調(diào)用的 script 標(biāo)簽之前 -->
              <script type="text/html" id="tpl">
                  {{if user}}
                  <h2>{{user.name}}</h2>
                  {{/if}}
              </script>
              <script>
                  var user={
                      name: 'Template username'
                  }
                  var html=template('tpl', {user: user})
                  var container=document.querySelector('#container');
                  container.innerHTML=html;
              </script>
          </body>
          </html>
          

          瀏覽器打開(kāi)看到的結(jié)果如下:


          通過(guò)瀏覽器渲染模板.png

          3 語(yǔ)法

          art-template 支持標(biāo)準(zhǔn)語(yǔ)法與原始語(yǔ)法。標(biāo)準(zhǔn)語(yǔ)法可以讓模板易讀寫(xiě),而原始語(yǔ)法擁有強(qiáng)大的邏輯表達(dá)能力。

          標(biāo)準(zhǔn)語(yǔ)法支持基本模板語(yǔ)法以及基本 JavaScript 表達(dá)式;原始語(yǔ)法支持任意 JavaScript 語(yǔ)句,這和 EJS 一樣。

          3.1 輸出


          標(biāo)準(zhǔn)語(yǔ)法

          {{value}}
          {{data.key}}
          {{data['key']}}
          {{a ? b : c}}
          {{a || b}}
          {{a + b}}
          

          原始語(yǔ)法

          <%=value %>
          <%=data.key %>
          <%=data['key'] %>
          <%=a ? b : c %>
          <%=a || b %>
          <%=a + b %>
          

          3.2 原文輸出


          標(biāo)準(zhǔn)語(yǔ)法

          {{@ value}}
          

          原始語(yǔ)法

          <%- value %>
          

          3.3 條件輸出


          標(biāo)準(zhǔn)語(yǔ)法

          <!-- 單 if 判斷 -->
          {{if value}} 
          ... 
          {{/if}}
          
          <!-- if ... else ... 判斷 -->
          {{if v1}} 
          ... 
          {{else if v2}}
           ... 
          {{/if}}
          

          原始語(yǔ)法

          <!-- 單 if 判斷 -->
          <% if (value) { %>
          ...
          <% } %>
          
          <!-- if ... else ... 判斷 -->
          <% if (v1) { %>
          ...
          <% else if (v2) { %>
          ...
          <% } %>
          

          3.4 循環(huán)輸出


          標(biāo)準(zhǔn)語(yǔ)法

          {{each target}}
            {{$index}} {{$value}}
          {{/each}}
          

          target是一個(gè)數(shù)組,each用于對(duì)數(shù)組遍歷,$index 是數(shù)組的下標(biāo), $value是數(shù)組的值 原始語(yǔ)法

          <% for (var i=0; i < target.length; i++) { %>
          <%=i %> <%=target[i] %>
          <% } %>
          

          注意:

          1. target 支持 array 與object 的迭代,其默認(rèn)值為 $data。
            具體看下面的例子:
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <meta http-equiv="X-UA-Compatible" content="ie=edge">
              <title>Document</title>
              <script src="./node_modules/art-template/lib/template-web.js"></script>
          </head>
          <body>
              <div id="container"></div>
              <script type="text/html" id="tpl">
                  <ul>
                      {{each user.arr}}
                      <li>
                          {{$index + 1}} ---- {{$value.type}} ---- {{$value.price}}
                          {{$data}}
                      </li>
                      {{/each}}
                  </ul>
              </script>
              <script>
                  var user={
                      obj: {
                          name: 'Bruce Lee',
                          age: 32,
                          gender: 'male'
                      },
                      arr: [
                          {type: 1, price: 10},
                          {type: 2, price: 12},
                          {type: 3, price: 18}
                      ] 
                  }
                  var html=template('tpl', {user: user})
                  var container=document.querySelector('#container');
                  container.innerHTML=html;
              </script>
          </body>
          </html>
          

          看輸出結(jié)果:


          each遍歷對(duì)象target(默認(rèn)為$data).png

          圖中可以看出$data其實(shí)就是傳入模板的總數(shù)據(jù)對(duì)象(原始數(shù)據(jù)對(duì)象)

          1. $value 與 $index 可以自定義:{{each target val key}}。
            具體看下面例子:
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <meta http-equiv="X-UA-Compatible" content="ie=edge">
              <title>Document</title>
              <script src="./node_modules/art-template/lib/template-web.js"></script>
          </head>
          <body>
              <div id="container"></div>
              <script type="text/html" id="tpl">
                  <h4>each 遍歷數(shù)組,采用默認(rèn)的索引 $index 和默認(rèn)的值 $value</h4>
                  <ul>
                      <!-- each 遍歷數(shù)組,采用默認(rèn)的索引 $index 和默認(rèn)的值 $value -->
                      {{each user.arr}}
                      <li>
                          {{$index}} ---- {{$value}}
                      </li>
                      {{/each}}
                  </ul>
          
                  <h4>each 遍歷數(shù)組, 采用自定義的索引 b 和默認(rèn)的值 a</h4>
                  <ul>
                      <!-- each 遍歷數(shù)組, 采用自定義的索引 b 和默認(rèn)的值 a -->
                      {{each user.arr b a}}
                      <li>
                          {{a}} ---- {{b}}
                      </li>
                      {{/each}}
                  </ul>
          
                  <h4>each 遍歷對(duì)象, 采用默認(rèn)的鍵 $index 和默認(rèn)的值 $value</h4>
                  <ul>
                      <!-- each 遍歷對(duì)象, 采用默認(rèn)的鍵 $index 和默認(rèn)的值 $value  -->
                      {{each user.obj}}
                      <li>
                          {{$index}} ---- {{$value}}
                      </li>
                      {{/each}}
                  </ul>
          
                  <h4>each 遍歷對(duì)象,采用自定義的鍵 key 和自定義的值 val</h4>
                  <ul>
                      <!-- each 遍歷對(duì)象,采用自定義的鍵 key 和自定義的值 val -->
                      {{each user.obj val key}}
                      <li>
                          {{key}} ---- {{val}}
                      </li>
                      {{/each}}
                  </ul>
              </script>
              <script>
                  var user={
                      obj: {
                          name: 'Bruce Lee',
                          age: 32,
                          gender: 'male'
                      },
                      arr: [
                          { type: 1, price: 10 },
                          { type: 2, price: 12 },
                          { type: 3, price: 18 }
                      ]
                  }
                  var html=template('tpl', { user: user })
                  var container=document.querySelector('#container');
                  container.innerHTML=html;
              </script>
          </body>
          </html>
          

          看輸出結(jié)果:


          each遍歷數(shù)組和對(duì)象以及自定義$data和$index.png

          3.5 定義變量

          標(biāo)準(zhǔn)語(yǔ)法

          {{set temp=data.sub.content}}
          

          原始語(yǔ)法

          <% var temp=data.sub.content %>
          

          3.6 模板繼承

          標(biāo)準(zhǔn)語(yǔ)法

          {{extend './layout.html'}}
          {{block 'head'}}
          ...
          {{/block}}
          

          原始語(yǔ)法

          <% extend ('./layout.html') %>
          <% block('head', function () { %>
          ...
          <% }) %>
          

          模板繼承允許你構(gòu)建一個(gè)包含站點(diǎn)共同元素的基本“模板骨架”,實(shí)例:

          <!--layout.art-->
          <!doctype html>
          <html>
          <head>
              <meta charset="utf-8">
              <title>{{block 'title'}}My Site{{/block}}</title>
          
              {{block 'head'}}
              <link rel="stylesheet" href="main.css">
              {{/block}}
          </head>
          <body>
              {{block 'content'}}{{/block}}
          </body>
          </html>
          
          <!--index.art-->
          {{extend './layout.art'}}
          
          {{block 'title'}}{{title}}{{/block}}
          
          {{block 'head'}}
              <link rel="stylesheet" href="custom.css">
          {{/block}}
          
          {{block 'content'}}
          <p>This is just an awesome page.</p>
          {{/block}}
          

          渲染 index.art 后,將自動(dòng)應(yīng)用布局骨架。

          3.7 子模板

          標(biāo)準(zhǔn)語(yǔ)法

          {{include './header.art'}}
          {{include './header.art' data}}
          

          原始語(yǔ)法

          <% include('./header.art') %>
          <% include('./header.art', data) %>
          

          看如下例子:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <meta http-equiv="X-UA-Compatible" content="ie=edge">
              <title>art-template-filter</title>
              <!-- 引入 template-web.js -->
              <script src="./node_modules/art-template/lib/template-web.js"></script>
          </head>
          <body>
              <div class="container"></div>
              <script type="text/html" id="filterTpl">
                  <h3>{{date | format 'YYYy-mM-dd' | addQuotationMarks}}</h3>
                  <h3><%=$imports.addQuotationMarks($imports.format(date)) %></h3>
              </script>
              <script>
                  var data={
                      date: Date.now(),
                  }
                  // 定義日期格式化過(guò)濾器 format 方法:
                  template.defaults.imports.format=function (date, format) {
                      if (!format || format.toLowerCase()==='yyyy-mm-dd') {
                          var dt=new Date(date);
                          var y=dt.getFullYear();
                          var m=(dt.getMonth() + 1).toString().padStart(2, '0');
                          var d=dt.getDate().toString().padStart(2, '0');
                          return `${y}/${m}/$4cayuku`;
                      } else {
                          return 'invalid date';
                      }
                  }
                  // 定義給字符串加引號(hào)過(guò)濾器 addQuotationMarks 方法:
                  template.defaults.imports.addQuotationMarks=function (str) {
                      return `"${str}"`;
                  }
                  // 調(diào)用 template 方法,渲染模板和數(shù)據(jù)
                  var html=template('filterTpl', data);
                  document.querySelector('.container').innerHTML=html;
              </script>
          </body>
          </html>
          

          注意:

          • {{date | format 'YYYy-mM-dd' | addQuotationMarks}}
            date 默認(rèn)為 format 過(guò)濾器(方法)的第一個(gè)參數(shù), 'YYYy-mM-dd' 才是format 過(guò)濾器的第二個(gè)參數(shù),date 經(jīng)過(guò) format 過(guò)濾器過(guò)濾后,得到的結(jié)果,又作為
            addQuotationMarks 過(guò)濾器的默認(rèn)參數(shù),如果有更多的過(guò)濾器,那么就把前一層過(guò)濾器過(guò)濾的結(jié)果,作為下一個(gè)過(guò)濾器的參數(shù)一層層過(guò)濾下去

          4 調(diào)試

          template.defaults.debug art-template 內(nèi)建調(diào)試器,能夠捕獲到語(yǔ)法與運(yùn)行錯(cuò)誤,并且支持自定義的語(yǔ)法。在 NodeJS 中調(diào)試模式會(huì)根據(jù)環(huán)境變量自動(dòng)開(kāi)啟:process.env.NODE_ENV !=='production' 設(shè)置 template.defaults.debug=true 后,等同于:

          {
              "cache": false,
              "minimize": false,
              "compileDebug": true
          }
          

          5 模板變量

          template.defaults.imports 模板通過(guò) $imports 可以訪問(wèn)到模板外部的全局變量和導(dǎo)入的變量。

          5.1 導(dǎo)入變量

          template.defaults.imports.log=console.log;
          
          <% $imports.log('Hello, template.defaults.imports.log') %>
          

          看下面例子:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <meta http-equiv="X-UA-Compatible" content="ie=edge">
              <title>template.defaults.imports</title>
              <script src="./node_modules/art-template/lib/template-web.js"></script>
          </head>
          <body>
              <div class="container">
              </div>
              <script type="text/html" id="importsTpl">
                  <% $imports.log('Hello, template.defaults.imports.log') %>
                  <%=$imports.date %>
              </script>
              <script>
                  var data={};
                  template.defaults.imports.log=console.log;
                  template.defaults.imports.date=new Date();
                  template.defaults.debug=true;
                  var html=template('importsTpl', data);
                  document.querySelector('.container').innerHTML=html;
              </script>
          </body>
          </html>
          

          注意:

          這些語(yǔ)法必須寫(xiě)在模板中,在模板中才會(huì)起作用;

          5.2 內(nèi)置變量清單

          • $data 傳入模板的數(shù)據(jù);
          • $imports 外部導(dǎo)入的變量以及全局變量;
          • print 字符串輸出函數(shù);
          • include 子模板載入函數(shù)
          • extend 模板繼承模板導(dǎo)入函數(shù)
          • block 模板塊生命函數(shù)

          最后,小編想說(shuō):我是一名python開(kāi)發(fā)工程師,

          整理了一套最新的python系統(tǒng)學(xué)習(xí)教程,

          想要這些資料的可以關(guān)注私信小編“01”即可(免費(fèi)分享哦)希望能對(duì)你有所幫助


          主站蜘蛛池模板: 亚洲一区电影在线观看| 欧美激情一区二区三区成人| 好吊视频一区二区三区| 国产福利电影一区二区三区,亚洲国模精品一区| av一区二区三区人妻少妇| 成人久久精品一区二区三区| 国产成人一区二区精品非洲| 日亚毛片免费乱码不卡一区| 亲子乱av一区二区三区| 在线观看国产一区二三区| 国产一区二区三区免费看| 一区二区三区国产| 无码日本电影一区二区网站| 国产日韩精品一区二区在线观看 | 久久综合九九亚洲一区| 毛片一区二区三区| 一区二区三区亚洲视频| 亚洲美女视频一区二区三区 | 视频一区二区在线播放| 亚洲AV乱码一区二区三区林ゆな| 亚洲乱码一区二区三区国产精品 | 成人一区专区在线观看| 国产av天堂一区二区三区| 亚洲欧美日韩中文字幕一区二区三区 | 国产一区二区三区在线看片| 久久久久一区二区三区| 国产伦理一区二区三区| 搡老熟女老女人一区二区| 无码AV动漫精品一区二区免费 | 亚洲av日韩综合一区二区三区| 亚洲国产成人久久一区WWW | 精品无码国产AV一区二区三区| 在线观看免费视频一区| 欧美日韩精品一区二区在线观看 | 国产天堂一区二区综合| 手机福利视频一区二区| 精品无码一区二区三区爱欲九九 | 色一情一乱一区二区三区啪啪高| 上原亚衣一区二区在线观看| 无码喷水一区二区浪潮AV| 精品无码一区在线观看|