python_day19_Django-3 (框架_模板)

MVC\MTV介紹
python_day19_Django-3 (框架_模板)

MVC介紹

  全名是Model View Controller,是軟件工程中的一種軟件架構模式,把軟件系統分爲三個基本部分:模型(Model)、視圖(View)和控制器(Controller),具有耦合性低、重用性高、生命週期成本低等優點。

用戶輸入URL到 [控制器],並響應用戶操作--> [視圖] 展示信息
                      --> 傳遞指令到 [模型],存數據到數據庫或取數據到 業務數據 --> 最後 [視圖] 展示信息
控制器: 傳遞指令,接收用戶輸入的指令
模型: 負責業務對象與數據庫的對象
視圖: 頁面展示給用戶

MTV介紹

  Django框架的不同之處在於它拆分的三部分爲:Model(模型)、Template(模板)和View(視圖),也就是MTV框架。

Model(模型):負責業務對象與數據庫的對象(ORM)
Template(模版):負責如何把頁面展示給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template

來源於 Django框架簡介
python_day19_Django-3 (框架_模板)


django模板語言

1.1、模板語言:常用格式

1.1.1、變量

    {{ name }}  

1.1.2、if

固定格式
    {% if ..... %} 
    {% endif %}
if 用法
    {% if 100 > nums %}
        {{ nums }}
    {% endif %}

if else 用法
    {% if 100 > nums %}
        {{ nums }}
    {% else %}
        {{ val }}
    {% endif %}

if in 當名稱在這個列表中
    {% if name in name_list %}
        {{ name }}
    {% else %}
        {{ val }}
    {% endif %}

1.1.3、for

固定格式
{% for .... %}
{% endfor %}

for用法
{% for i in num_list %}
    {{ forloop.counter }} 統計從列表的行 
    {{ forloop.last }}  最後一個值
{% endfor %}

1.2、模板語言:Filter

  在變量的基礎上做一些額外的操作, 語法: {{ value|filter_name:參數 }}, Filter一定要注意的是 value|filter_name左右都沒有空格

default

views函數     項目視圖函數中增加
def t_test(request):
     # 傳遞一個對象到html頁面中
    f_str = "test value"
    return render(
        request,
        "t_test.html",
        {"fstr": f_str},
    )

html頁面
# 如果fstr爲空,那麼在頁面中顯示的就是Null   nulls是一個對比名
{{ fstr|default:"Null" }}
{{ nulls|default:"the value Null" }}

lenght

    {{ fstr|length }}   獲取元組的長度

配合if使用  當大於3時打印第一步,否則打印else
{%  if fstr|length > 3 %}
    <p>gt 3</p>
{% else %}
    <p>lt 3</p>
{% endif %}

獲取列表的長度
l_str = ["1a","2bbe","3ccc"]
{{ lstr|length }}   統計的是列表的長度
如果想統計單個值的長度,可以使用切片的方式取出{{ lstr.1|length }}

formatsize

視圖函數
filesize = 10240000
{"fstr": f_str, "lstr": l_str, "fsize": filesize},

html
{{ fsize|filesizeformat }}
單位  B/KB/MB......

date

t_time = datetime.now()
字典中添加 {"fstr": f_str, "lstr": l_str, "fsize": filesize,"now" : t_time},

html頁面
{{ now|date:"Y-m-d H:i:s" }}

頁面顯示結果: 2018-07-09 16:37:57

safe
Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,如果自動轉義的話顯示的就是HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,如果是一個單獨的變量我們可以通過過濾器“|safe”的方式告訴Django這段代碼是安全的不必轉義

比如: 例一
t_html = "<p>p標籤</p>"
字典中添加: "t_html" : t_html,

html
{{ t_html }}

頁面中顯示的就是   <p>p標籤</p>

如果添加了safe
{{ t_html|safe }}  不進行轉義 那就直接就是一個p標籤, 如果用戶XSS×××那麼必將造成一定的風險

比如: 評論用戶在評論中直接輸入
<script> (for (i;;) alert(ssss);;) </script>  輸入死循環,那麼程序將會直接卡死,此處就不應該進行轉義

truncatechars
  如果字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(“...”)結尾。
格式: value| truncatechars:截斷的字符數

g_str = "真正優秀的人,從來不怕成功遲到, 堅守一顆執着的心,終會實現心中的夢想"
字典中添加 "g_str": g_str

html頁面
     {{ g_str|truncatechars:20 }}

顯示: 真正優秀的人,從來不怕成功遲到, ...    

自義定filter

在項目下創建一個python包  templatetags   固定名稱
創建一個名爲myfirst.py文件
from django import template

# 必須首先創建一個全局register變量,它是用來註冊你自定義標籤和過濾器的
register = template.Library()

@register.filter(name="tg")
def first_reg(arg):
    return "{} myfirst".format(arg)
    # 結果: test value myfirst

@register.filter(name="tg2")
# 一個參數放變量值,一個用來放選項值
def two_reg(arg1,arg2):
    # arg1 爲模板定義的對象 就等於是 fstr
    # arg2 爲手動輸入的值 {{ fstr|tg2:"xiong" }}
    return "{}--{}".format(arg1,arg2)
    # 結果:test value--xiong

html頁面中引用
需要先導入:  {% load myfirst %}   這個是創建的Py文件的名稱
這個是隻有一個對象的函數
{{ fstr|tg }}

這個是有兩個arg的函數
{{ fstr|tg2:"xiong" }}

1.3、模板語言:Tags

for

html頁面
<ol>
    {% for uList in lstr %}
        <li>{{ uList }}</li>
    {% endfor %}
</ol>
<ul>
    {% for uList in lstr %}
        {% if forloop.first %}
            <p>第一個: {{ uList }}</p>
        {% endif %}
    {% endfor %}
</ul>

頁面展示爲: 第一個: 1a

<ul>
    {% for uList in lstr %}
        {% if forloop.last %}
            <p>最後一個: {{ uList }}</p>
        {% endif %}
    {% endfor %}
</ul>

頁面展示爲: 最後一個: 3ccc

靜態方法: inclusion_tag

1、url中添加訪問路徑
    path("test/", views.test)

2、項目view中添加
def test(request):
    return render(request, "pags.html")

3、template/page.html 導入模塊
    {% load xx %}
    {% tagss 10 %}

4、項目下創建 templatetags
from django import template

register = template.Library()

@register.inclusion_tag("ul.html")
def tagss(arg):
    arg = 1 if arg < 1 else int(arg)
    data = ["這是第{}號".format(i) for i in range(1, arg)]
    return {"data" : data}

5、創建一個html
<ul>
    {% for foo in data %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>

6、最終頁面效果
這是第1號
這是第2號
........

路由系統

   說明:以下使用django2.x urlConf寫法

URL conf 2.0官方文檔

1、django 1.1與2.0 url conf 寫法:
   1.1寫法 url(r'xx/[0-9]{2}/$')      意爲: http://urlpath/xx/2個數字 [10-99] 
   2.0寫法 re_path("xx/[0-9]{2}/$")

2、普通寫法
    語法 urls文件 urlpatterns = [
                 path('urls/', 視圖.函數),
        ]

2.1、正則表達式

官網案例
from django.urls import path, re_path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
]

案例對比:
from django.urls import re_path

urlpatterns = [
    re_path(r'^blog/(page-(\d+)/)?$', blog_articles),                  # bad
    re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments),  # good
]
案例一
項目下的 urls.py文件
導入re_path
    from django.urls import path, re_path 
    urlpatterns = [
            re_path('test/([0-9]{2}/$)', views.retest)
    ]

app下定義 views.py文件
def retest(request,nums):
    print(nums)
    return render(request, "retest_page.html",{"nums":nums})

定義templates目錄 新建retest_page.html
<p>{{ nums }}</p>

效果

python_day19_Django-3 (框架_模板)

 注:當需要導入多個app時有多個view視圖就需要使用別名
from app01 import views as app01_view
from app02 import views as app02_view
urlpatterns = [
    path('app01/',app01_view.app_test),
    path('app02/',app02_view.app_test),
    ]
案例二
導入re_path
    from django.urls import path, re_path 
    urlpatterns = [
            re_path(r'^test2/(?P<name>[a-zA-Z]{1,5})/(?P<age>[0-9]{1,3})/$', views.retest2),
    ]

app下定義 views.py文件
def retest2(request,name,age):
    print(name,age)
    return HttpResponse(name,age)

定義templates目錄 新建retest_page.html
<p>名稱: {{ name }}</p>
<p>年齡: {{ age }}</p>

效果

python_day19_Django-3 (框架_模板)

2.2、include其他的URLconfs

案例一:單個app導入
1、創建一個app
    python manage.py startapp appname
    創建完之後需要在項目下的settings的INSTALLED_APPS中添加'app02.apps.App02Config',

2、app下創建urls.py文件
    from django.urls import path, re_path
    from . import views

    urlpatterns = [
            re_path('app01/$', views.app_test),
            ]

3、創建app01對應函數以及視圖
    def app_test(request):
            return HttpResponse('app01.app_test')

4、項目中include該app
    re_path('^ptest/',include('app01.urls')),

5、展示效果,  訪問一定是項目urls定義的名稱/app定義的path名稱

python_day19_Django-3 (框架_模板)

案例二:多個app
項目名:pre
app名稱: app01 與 app02
初始與單個app的第一第二步一樣,都需要配置 setting文件以及導入相應的path

1、urls配置文件
from django.urls import path, re_path
from . import views

urlpatterns = [    # app01 app02定義的path要不相同
    re_path('app01/$', views.app_test),
    ]

2、views配置 文件
from django.shortcuts import render, HttpResponse

def app_test(request):    # 注意響應到頁面的展示效果
    return HttpResponse('app02.app_test2')

3、pre項目下配置
from app01 import views as app01_view
from app02 import views as app02_view
urlpatterns = [
    path('app01/',include('app01.urls')),
    path('app02/',include('app02.urls')),
    ]

效果:

python_day19_Django-3 (框架_模板)

2.3、反向解析url

功能: 當path的路徑名稱變更時,別名不動,在html頁面中定義的a標籤頁面就不會受到影響,否則當path路徑變更時,就需要修改html中a標籤的路徑地址

大致思路:
1、先定義urls,路徑以及函數名稱,
2、配置view視圖函數,定義urls中配置的函數名稱,以及要響應的文件
3、配置對應的templates html頁面模板

1、定義項目urls,導入其它應用下的urls文件
from django.urls import path, re_path, include
urlpatterns = [
    path('app01/', include('app01.urls')),
]

2、app應用下的urls文件
from django.urls import path, re_path
from . import views

urlpatterns = [
    path('atest/', views.atest, name='asatest'),     # name 對應path路徑的別名
    path('btest/', views.btest, name='asbtest'),
]

3、app應用下的view視圖函數、
def atest(request):
    return render(request, 'atest.html')

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

4、配置templates下的html頁面
templates/btest.html
<h1>btest page</h1>       
<a href="{% url 'asatest' %}">跳轉到a頁面</a>

templates/atest.html
<h1>atest page</h1>
<a href="{% url 'asbtest'  %}">跳轉到b頁面</a>

5、最終效果
     path名稱 app01/atest 如果修改成別的 點擊跳轉時依舊正常

python_day19_Django-3 (框架_模板)

官網示例

示例
Consider again this URLconf entry:

from django.urls import path

from . import views

urlpatterns = [
    #...
    path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
    #...
]
According to this design, the URL for the archive corresponding to year nnnn is /articles/<nnnn>/.

You can obtain these in template code by using:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
Or in Python code:

from django.http import HttpResponseRedirect
from django.urls import reverse

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

2.4、反向解析URL命名空間

項目中定義: namespace
應用中需要定義: name
html頁面中引用: {% url 'namespace:name' %}

項目名稱:upload
應用兩個:app01,app02

案例引用了:  
    從其它頁面引用 :include ,
    命名空間:namespace,
    別名:name,
    html引用: {% url 'ss' %}

1、項目urls定義
from django.urls import path, re_path, include
from app01 import views as app01_view
from app02 import views as app02_view

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/', include(('app01.urls', 'app01-pool'),namespace='app01-pool')),
    path('app02/', include(('app02.urls', "app02-pool"),namespace='app02-pool'))
]

2、app中urls中定義,  app01 app02的urls一樣
from django.urls import path
from . import views

urlpatterns = [
    path('aaa/', views.atest, name='asatest'),
    path('bbb/', views.btest, name='asbtest'),
]

3、app中view定義, app01 app02的view
from django.urls import path
from . import views

urlpatterns = [
    path('aaa/', views.atest, name='asatest'),
    path('bbb/', views.btest, name='asbtest'),
]

4、namespace引用 語法     url 'namespace:name'
<h1>a2 test page</h1>
<a href="{% url 'app01-pool:asbtest' %}">跳轉到app01的atest頁面</a>

html大致引用    app01 a頁面跳到b頁面,b頁面跳到app02的a頁面,然後app02的a頁面在跳到app02的b頁面,最終在跳回app01的a頁面

atest
    <a href="{% url 'app01-pool:asbtest'  %}">跳轉到app01-btest頁面</a>
btest
    <a href="{% url 'app02-pool:asatest' %}">跳轉到app02-atest頁面</a>
a2test
    <a href="{% url 'app02-pool:asbtest' %}">跳轉到app02的btest頁面</a>
b2test
    <a href="{% url 'app01-pool:asatest' %}">跳轉到app01的atest頁面</a>

5、最終測試效果

python_day19_Django-3 (框架_模板)

異常錯誤:

'Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.'

我的代碼爲:
urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/', include(('app01.urls', namespace='app01-pool')),
    path('app02/', include(('app02.urls',namespace='app02-pool')),
]

解決大致思路:https://blog.csdn.net/zoulonglong/article/details/79612973

最終解決辦法:  def include(arg, namespace=None):
  arg就是('app02.urls', "app02-pool")已經被佔用了,而namespace沒有被定義所以報錯
urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/', include(('app01.urls', 'app01-pool'),namespace='app01-pool')),
    path('app02/', include(('app02.urls', "app02-pool"),namespace='app02-pool'))
]
官網案例:
urls.py
from django.urls import include, path

urlpatterns = [
    path('author-polls/', include('polls.urls', namespace='author-polls')),
    path('publisher-polls/', include('polls.urls', namespace='publisher-polls')),
]
polls/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    ...
]
Using this setup, the following lookups are possible:

If one of the instances is current - say, if we were rendering the detail page in the instance 'author-polls' - 'polls:index' will resolve to the index page of the 'author-polls' instance; i.e. both of the following will result in "/author-polls/".

In the method of a class-based view:

reverse('polls:index', current_app=self.request.resolver_match.namespace)
and in the template:

{% url 'polls:index' %}

2.5、母版

base頁面
<head>
    <meta charset="UTF-8">
    {% block title %}
    {% endblock %}
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <link rel="stylesheet" href="/static/fontAwesome/css/font-awesome.css">
</head>
<body>

<div class="container">
    {% block context %}
    {% endblock %}
</div>

<script src="/static/jquery-3.3.1.js"></script>
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
</body>

繼承頁面
{% extends 'base.html' %}
{% block title %}blog titles{% endblock %}
{% block context %}
<div class="row text-center">
<h1>我的博客</h1>
</div>
<div class="row">
    <div class="col-xs-12 col-md-8">
        <ul>
            {% for foo in blog_title %}
                <li>{{ foo.title }}</li>
            {% endfor %}
        </ul>
    </div>
</div>
{% endblock %}
在base.html 中已經定義了{% block title % }和{% block content% }塊, 語句@和則是在本模板文件中對“父模板” base.html 中的同名稱塊標籤進行重寫。

項目下的url.py
from django.urls import path, include
urlpatterns = [
    path('admin/', admin.site.urls),
     # urlpath路徑名稱  導入include , 反向URL解析
    path('blog/', include(('blog.urls',"blog-pool"), namespace='blog')),
]

應用下的urls.py
from django.urls import path,re_path
from blog import views

urlpatterns = [
    re_path('', views.blog_title),
]

應用下的視圖函數  view 類於函數的視圖
from django.shortcuts import render
from .models import BlogArticles
# Create your views here.

def blog_title(request):
    blogs = BlogArticles.objects.all()
    return render(request, "blog/titles.html", {"blog_title": blogs})

應用下的models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
# Create your models here.

class BlogArticles(models.Model):
    title = models.CharField(max_length=300)
    author = models.ForeignKey(User, related_name="blog_posts",on_delete=models.CASCADE)
    body = models.TextField()
    publish = models.DateTimeField(default=timezone.now())

    def __str__(self):
        return self.title

最終效果

python_day19_Django-3 (框架_模板)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章