1. 程式人生 > >django框架之視圖系統和路由系統

django框架之視圖系統和路由系統

沒有 *args mat rap 其他 自己 XML func quest

內容回顧:

    1. tags
1. for循環
{% for name in name_list %}
{{ name }}
{% endfor %}

{% for name in name_list %}
{{ name }}
{% empty %}
空空如也
{% endfor %}

forloop { }
forloop.counter 當前循環的索引值 從1開始
forloop.counter0 當前循環的索引值 從0開始
forloop.revcounter 當前循環的索引值(倒序) 到1結束
forloop.revcounter0 當前循環的索引值(倒序) 到0結束
forloop.first 單前循環是否是第一次循環 布爾值
forloop.last 單前循環是否是最後一次循環 布爾值
forloop.parentloop 當前循環的外層循環

上臺階,可以一次上1個臺階,可以上2個臺階,可以上3個臺階。問有n個臺階,有多少種走法?
2. if判斷
{% if 條件 %}
操作
{% endif %}

{% if 條件 %}
操作
{% else %}
其他操作
{% endif %}

{% if 條件 %}
操作
{% elif 條件 %}
不同操作
{% else %}
其他操作
{% endif %}
註意事項:
1. 不能連續判斷 a > b > C 用and連接
2. 不支持算數運算 +-*/ 用filter
3. csrf_tokrn
使用:在form表單中使用
效果:添加了一個隱藏的input標簽,標簽名叫csrfmiddlewaretoken 值:隨機字符串
作用:提交POST請求
4. 註釋 {# 註釋部分 #}

2. 母板和繼承
1.為什麽要用母板和繼承:
很多頁面有重復或相似的代碼,減少代碼的重復和修改方便才用母板和繼承
2.具體步驟:
1. 創建一個母板,‘base.html‘ 將多個頁面的重復代碼提取出來
2. 在母板中定義多個block,來區分不同頁面的不同內容
3. 在子頁面中繼承母板 {% extends ‘base.html‘ %}
4. 在block中寫自己頁面獨特的內容

3. 註意事項
1. {% extends ‘base.html‘ %} 寫在第一個行
2. {% extends ‘base.html‘ %} base.html加上引號 不然當做是變量
3. 通常定義多個block,還有一個page-css 和 page-js
3. 組件
將一小部分的HTML代碼寫在一個模板中。———》 組件
在其他的頁面中 {% include ‘nav.html‘ %}

4. 靜態文件的內容
{% load static %}
"{% static ‘css/mycss.css‘ %}" ——》 /static/css/mycss.css

{% get_static_prefix %} —— 》 /static/

"{% get_static_prefix %}css/mycss.css"


5. 自定義simple_tag 和 inclusion_tag

今日內容:

視圖系統

視圖:

一個視圖函數(類),簡稱視圖,是一個簡單的Python 函數(類),它接受Web請求並且返回Web響應。

響應可以是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片。

簡單的說我們通常在views寫的就是視圖。只不過我們寫的是基於函數的視圖,即FBV。把視圖寫成基於類的,就是CBV啦。

這是FBV

def add_publisher(request):
    new_name = ‘‘
    err_msg = ‘‘
    if request.method == POST:
        new_name = request.POST.get(
publisher_name) if new_name: publisher_obj_list = models.Publisher.objects.filter(name = new_name) if not publisher_obj_list: models.Publisher.objects.create(name = new_name) return redirect(/publisher/) else: err_msg
= 數據已存在 else: err_msg = 數據不能為空 return render(request, add_publisher.html, {old_name: new_name, err_msg: err_msg})

改成這樣就是CBV啦:

from django.views import View
class Addpublisher(View):
    def get(self,request):
        return render(request, add_publisher.html)
    def post(self,request):
        new_name = request.POST.get(publisher_name)
        publisher_obj_list = models.Publisher.objects.filter(name=new_name)
        if not publisher_obj_list:
            models.Publisher.objects.create(name=new_name)
            return redirect(/publisher/)
        else:
            err_msg = 數據已存在
            return render(request, add_publisher.html,{err_msg:err_msg})

往深入的講,他其實是實現了View中的dispatch方法,所以這個dispatch我們可以自己定義:讓他去執行父類的dispatch方法:

from django.views import View
class Addpublisher(View):
    def dispatch(self, request, *args, **kwargs):
      print(‘處理請求之前‘) ret =
super().dispatch(self, request, *args, **kwargs)     print(‘處理請求之後‘)

def get(self,request):
     print(‘這是get請求‘)
return render(request, add_publisher.html) def post(self,request): new_name = request.POST.get(publisher_name) publisher_obj_list = models.Publisher.objects.filter(name=new_name) if not publisher_obj_list: models.Publisher.objects.create(name=new_name) return redirect(/publisher/) else: err_msg = 數據已存在 return render(request, add_publisher.html,{err_msg:err_msg})

其實這個dispatch相當於裝飾器的作用。

簡版的流程:
AddPublisher.as_view() ——》 view 函數
當請求來的時候才執行view
view中執行:
1. 先實例化AddPublisher,給self
2. 執行self.dispatch()
self 有dispatch 就執行自己的
沒有就是執行 父類(View)的dispatch方法
3. dispatch中執行:
先通過反射獲取到AddPublisher中定義get或者post方法。
執行get或者post方法 返回httpresponse對象
4. view接收到dispatch的返回值——httpresponse對象
5. view返回httpresponse對象

接下來我們給視圖加上裝飾器:

  裝飾器的作用是在函數之前或者之後做一些操作,並且不改變函數的調用方式。

  

def wrapper(func):
    def inner(*args,**kwargs):
        now = time.time()
        ret = func(*args,**kwargs)
        print(函數執行的時間是{}.format(time.time()-now))
        return ret
    return inner
#增加出版社
@wrapper
def add_publisher(request):
    new_name = ‘‘
    err_msg = ‘‘
    if request.method == POST:
        new_name = request.POST.get(publisher_name)
        if new_name:
            publisher_obj_list = models.Publisher.objects.filter(name = new_name)
            if not publisher_obj_list:
                models.Publisher.objects.create(name = new_name)
                return redirect(/publisher/)
            else:
                err_msg = 數據已存在
        else:
            err_msg = 數據不能為空
    return render(request, add_publisher.html, {old_name: new_name, err_msg: err_msg})

接下來我們給CBV加上裝飾器:

from django.views import View
from django.utils.decorators import method_decorator
class Addpublisher(View):
    # def dispatch(self, request, *args, **kwargs):
    #     return super().dispatch(self, request, *args, **kwargs)

    @method_decorator(wrapper)  #為get請求加上裝飾器
    def get(self,request):
        return render(request, add_publisher.html)
def post(self,request): new_name = request.POST.get(publisher_name) publisher_obj_list = models.Publisher.objects.filter(name=new_name) if not publisher_obj_list: models.Publisher.objects.create(name=new_name) return redirect(/publisher/) else: err_msg = 數據已存在 return render(request, add_publisher.html,{err_msg:err_msg})

給dispatch方法加上裝飾器,get和post請求就都加上裝飾器了。

如果要在類上加裝飾器,就要這樣寫@method_decorator(wrapper,name=‘get‘)

                @method_decorator(wrapper,name=‘post‘)

 request對象:

    request屬性:
request.method 請求方式 GTE POST
request.GET ——》 字典 URL上傳的參數
request.POST ——》 字典 form表單傳的參數

    request.FILES 上傳的文件

   request.path_info 返回用戶訪問url,不包括域名

    request.body 請求體,byte類型 request.POST的數據就是從body裏面提取到的(gest請求沒有請求體)

  我們來寫一個上傳的實例

views中的代碼:

def upload(request):
    if request.method == POST:
        print(request.FILES)
        upload_obj = request.FILES[file_name]
        with open(upload_obj.name,wb)as f:
            for chunk in upload_obj.chunks():
                f.write(chunk)
    return render(request,upload.html)

html的代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action=""method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="file" name="file_name" >
    <button>提交</button>
</form>
</body>
</html>

request方法:

  request.path_info url路徑不包含url參數和域名

  request.get_full_path() url路徑包含url參數

  request.get_host() 獲取ip和端口

Response對象

response方法:

1. HttpResponse 類 字符串
2. render 返回一個HTML頁面
3. redirect 跳轉 重定向 Location:/index/

response屬性:

  HttpResponse.content:響應內容

  HttpResponse.charset:響應內容的編碼

  HttpResponse.status_code:響應的狀態碼

  

JsonResponse對象:

我們先寫一個json數據:

def json_data(request):
    import json
    data = {name:alex,age:73}
    return HttpResponse(json.dumps(data))

然後我們在試一試django為我們提供的方法:

from django.http import JsonResponse
def json_data(request):
    # import json
    data = {name:alex,age:73}
    # return HttpResponse(json.dumps(data))
    return  JsonResponse(data)

我們來說一說這兩者的區別:

  如果瀏覽器拿到的是JsonResponse的格式會自動幫你解析。而且JsonResponse只會返回字典,如果要返回列表,JsonResponse(data,safe=False)

路由系統:

基本格式:

urlpatterns = [
     url(正則表達式, views視圖,參數,別名),]
urlpatterns = [
    url(r^articles/2003/$, views.special_case_2003),
    url(r^articles/([0-9]{4})/$, views.book),
    url(r^articles/([0-9]{4})/([0-9]{2})/$, views.book),
    url(r^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$, views.book),

]
我們匹配的時候加上小括號就是分組了,他就會將小括號裏的內容以參數的形式傳給views中的函數,而views中的
函數就需要參數來接受。
def book(request,*args):
    print(args)
    return HttpResponse(o98k)

我們把這樣的匹配叫做無名分組

註意事項

  1. urlpatterns中的元素按照書寫順序從上往下逐一匹配正則表達式,一旦匹配成功則不再繼續。
  2. 若要從URL中捕獲一個值,只需要在它周圍放置一對圓括號(分組匹配)。
  3. 不需要添加一個前導的反斜杠,因為每個URL 都有。例如,應該是^articles 而不是 ^/articles。
  4. 每個正則表達式前面的‘r‘ 是可選的但是建議加上。
分組命名匹配:
在Python的正則表達式中,分組命名正則表達式組的語法是(?P<name>pattern),其中name是組的名稱,pattern是要匹配的模式。

我們也可以在分組的時候加上名字,比如:
url(r‘^book/(?P<year>[0-9]{4})/[0-9]{2}‘,views.book),

這樣views中的book函數在接受的時候就需要一個同名的參數來接受不然就會報錯。
def book(request,year):
    print(year)
    return HttpResponse(o98k)

這就是命名分組!

一個公司會有不同的業務,也會有不同的app,這樣我們在寫url的時候就可能會有重復。

我們在項目名下的urls.py文件裏可以這樣寫:

from django.conf.urls import url,include
from app01 import urls
urlpatterns = [
    url(r‘app01/‘,include(urls))
]

剩下的就交給app01來做了。

我們現在app01建一個urls.py文件,在文件中這樣寫:

from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r^book/(?P<year>[0-9]{4})/[0-9]{2},views.book),
]

然後再views的文件中寫book函數:

def book(request,year):
    print(year)
    return HttpResponse(o98k)

同樣我們也可以有多個app文件。

項目名的urls.py文件下這樣寫:

from django.conf.urls import url,include
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
    url(rapp01/,include(app01_urls)),
    url(rapp02/,include(app02_urls))
]

在app01創建一個urls的py文件寫:

from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r^book/(?P<year>[0-9]{4})/[0-9]{2},views.book),
]

在app02創建一個urls的py文件寫:



from django.conf.urls import url
from app02 import views
urlpatterns = [
    url(r^book/(?P<year>[0-9]{4})/[0-9]{2},views.book),
]

然後分別寫好app01和app02下的book函數。

命名URL和URL反向解析:

我們在 url後面加上一個名字,name屬性,這樣:

url(r‘^json_data/‘,views.json_data,name=‘data‘),
就可以在views的函數中進行向解析 print(reverse(‘data‘))
具體代碼就是這樣的:

url(r^json_data/,views.json_data,name=‘josn_data),
在views函數中:
def json_data(request):
    print(reverse(‘ison_data))
    data = {name:alex,age:73}
    return  JsonResponse(data)

打印出來的結果就是:/json_data/。

在模板裏面可以這樣引用:

{% url ‘jaon_data‘ %}


說的簡單點就是在url起一個名字,然後reverse通過這個名字反向解析拿到url地址。



參數是這樣傳的:
無名傳參:
url(r‘^book/([0-9]{4})/[0-9]{2}‘,views.book,name=‘book‘)
  函數中的參數:
  reverse(‘book‘,args=(‘1995‘))
  模板中的參數:
  {%url ‘book‘ ‘1995‘%}

 命名傳參:

url(r‘^book/(?<Pmouth>[0-9]{4})/[0-9]{2}‘,views.book,name=‘book‘)
  函數中的參數:
  reverse(‘book‘,kwargs={‘mouth‘:‘1995‘})
  模板中的參數:
  {%url ‘book‘ mouth=‘1995‘%}
 namespace:
如果說qpp01下和app02下有相同name的url,那麽在視圖中反向解析的時候找的會是誰的url呢?這就需要在項目名下的include裏加一個參數
namespace=‘app01‘,namespace=‘app02‘,然後再視圖中reverse(‘app01:index‘)
                           reverse(‘app02:index‘)
                     在模板中也是一樣{%url ‘app01:index‘%}

舉個例子:


project中的urls.py



技術分享圖片
from django.conf.urls import url, include
 
urlpatterns = [
    url(r^app01/‘, include(app01.urls‘, namespace=app01)),
    url(r^app02/‘, include(app02.urls‘, namespace=‘app02)),
]
技術分享圖片

app01中的urls.py



技術分享圖片
from django.conf.urls import url
from app01 import views
 
app_name = app01
urlpatterns = [
    url(r^(?P<pk>\d+)/$‘, views.detail, name=detail)
]
技術分享圖片

app02中的urls.py



技術分享圖片
from django.conf.urls import url
from app02 import views
 
app_name = app02
urlpatterns = [
    url(r^(?P<pk>\d+)/$‘, views.detail, name=detail)
]
技術分享圖片

現在,我的兩個app中 url名稱重復了,我反轉URL的時候就可以通過命名空間的名稱得到我當前的URL。


語法:


‘命名空間名稱:URL名稱‘


模板中使用:



{% url ‘app01:detail‘ pk=12 %}

views中的函數中使用



v = reverse(app01:detail‘, kwargs={pk‘:11})
 這樣即使app中URL的命名相同,我也可以反轉得到正確的URL了。
 

 

django框架之視圖系統和路由系統