1. 程式人生 > >Django 路由層,檢視層,模板層

Django 路由層,檢視層,模板層

MVC與MTV模型

一、MVC

Web伺服器開發領域裡著名的MVC模式,所謂MVC就是把Web應用分為模型(M),控制器(C)和檢視(V)三層,他們之間以一種外掛式的、鬆耦合的方式連線在一起,模型負責業務物件與資料庫的對映(ORM),檢視負責與使用者的互動(頁面),控制器接受使用者的輸入呼叫模型和檢視完成使用者的請求,其示意圖如下所示:

二、MTV

Django的MTV模式本質上和MVC是一樣的,也是為了各元件間保持鬆耦合關係,只是定義上有些許不同,Django的MTV分別是:

  • M 代表模型(Model): 負責業務物件和資料庫的關係對映(ORM)。
  • T 代表模板 (Template):負責如何把頁面展示給使用者(html)。
  • V 代表檢視(View): 負責業務邏輯,並在適當時候呼叫Model和Template。
  • 除了以上三層之外,還需要一個URL分發器,它的作用是將一個個URL的頁面請求分發給不同的View處理,View再呼叫相應的Model和Template,MTV的響應模式如下所示:

Django的下載與基本命令

  • 下載Django:pip3 install django==2.0.1
  • 建立一個django project: django-admin.py startproject luffy
  • 在mysite目錄下建立應用:python manage.py startapp app01
  • 啟動django專案:python manage.py runserver 8080 我們訪問:http://127.0.0.1:8080/時就可以看到:

一、檔案介紹

  • manage.py ----- Django專案裡面的工具,通過它可以呼叫django shell和資料庫等。
  • settings.py ---- 包含了專案的預設設定,包括資料庫資訊,除錯標誌以及其他一些工作的變數。
  • urls.py ----- 負責把URL模式對映到應用程式。

靜態檔案

?
1 2 3 4 5 #在settings.py中: STATIC_URL = '/static/' STATICFILES_DIRS = (      os.path.join(BASE_DIR, 'static' ), )

路由

URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要為該URL呼叫的檢視函式之間的對映表;你就是以這種方式告訴Django,對於客戶端發來的某個URL呼叫哪一段邏輯程式碼對應執行。

一、簡單的路由配置

  • 若要從URL 中捕獲一個值,只需要在它周圍放置一對圓括號。
  • 不需要新增一個前導的反斜槓,因為每個URL 都有。例如,應該是^articles 而不是 ^/articles。
  • 每個正則表示式前面的'r' 是可選的但是建議加上。它告訴Python 這個字串是“原始的” —— 字串中任何字元都不應該轉義
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 在urls.py中: from django.urls import path,re_path from app01 import views   # 路由配置: 路徑--------->檢視函式 urlpatterns = [      path( 'admin/' , admin.site.urls),        #無名分組:捕獲的值作為位置引數傳遞給檢視函式      re_path(r '^articles/([0-9]{4})/$' , views.year_archive), #year_archive(request,'2009')      re_path(r '^articles/([0-9]{4})/([0-9]{2})/$' , views.month_archive), # month_archive(request,'2009','12')      re_path(r '^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$' , views.article_detail), # month_archive(request,'2009','12','1'),# month_archive(request,'2009','12','13')        #有名分組:捕獲的值作為關鍵字引數傳遞給檢視函式      re_path(r '^articles/(?P<year>[0-9]{4})/$' , views.year_archive), # month_archive(request, year='2005')      re_path(r '^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$' , views.month_archive), # month_archive(request, year='2005', month='03')      re_path(r '^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$' , views.article_detail), # month_archive(request, year='2003', month='03', day='03')   ]

二、分發

?
1 2 3 4 5 6 7 8 9 10 11 # 在urls.py中: from django.urls import path, re_path, include   urlpatterns = [      path( 'admin/' , admin.site.urls),        # 分發      re_path(r "^app01/" , include( "app01.urls" )),      re_path(r "^app02/" , include( "app02.urls" )),      re_path(r "^" , include( "app01.urls" )), ]

三、反向解析

獲得URL 的最終形式,,對於不同層級,Django 提供不同的工具用於URL 反查:

  • 在模板中:使用url 模板標籤。
  • 在Python 程式碼中:使用from django.urls import reverse
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 # 在urls.py中: from django.urls import path,re_path,include from app01 import views    urlpatterns = [      path( 'admin/' , admin.site.urls),         # 反向解析      path( 'login.html/' ,views.login,name = "Log" ),      re_path(r '^articles/([0-9]{4})/$' , views.year_archive, name = 'news-year-archive' ),    ]    # 在模板中:注意引數 """ <form action="{% url 'Log' %}" method="post"></form>    <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> <!--多個引數--> <a href="{% url "n4" i1 i2 %}">編輯</a> """    #在views.py中: from django.urls import reverse from django.shortcuts import render,HttpResponse,redirect    def redirect_to_year(request):      # 無參      url = reverse( 'Log' )      print (url)         #有參      year = 2006      url99 = reverse( 'news-year-archive' , args = (year,))      print (url99)      return HttpResponse( 'OK' )

四、名稱空間

名稱空間(英語:Namespace)是表示識別符號的可見範圍。一個識別符號可在多個名稱空間中定義,它在不同名稱空間中的含義是互不相干的。我們在開發專案時,會經常使用name屬性反解出URL,當不小心在不同的app的urls中定義相同的name時,可能會導致URL反解錯誤,為了避免這種事情發生,引入了名稱空間。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 # 在urls.py中: from django.urls import path, re_path, include   urlpatterns = [      path( 'admin/' , admin.site.urls),        # 分發      re_path(r "^app01/" , include( "app01.urls" )),      re_path(r "^" , include( "app01.urls" )),        # 兩個應用中,URL 模式名字一樣時:      re_path(r "^app01/" , include(( "app01.urls" , "app01" ))),      re_path(r "^app02/" , include(( "app02.urls" , "app02" ))),   ]   #app01中的urls.py from django.urls import path,re_path from app01 import views   urlpatterns = [     re_path( "index/" ,views.index,name = "index" ) ]   #app02中的urls.py from django.urls import path,re_path from app02 import views   urlpatterns = [     re_path( "index/" ,views.index,name = "index" ) ]   #app01中的views.py from django.shortcuts import render,HttpResponse from django.urls import reverse def index(reqeust):      return HttpResponse(reverse( "app01:index" ))   #app02中的views.py from django.shortcuts import render,HttpResponse from django.urls import reverse def index(reqeust):      return HttpResponse(reverse( "app02:index" ))

五、django2.0版的path

1、基本例項

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 在urls.py中: from django.urls import path, re_path from app01 import views urlpatterns = [      re_path( 'articles/(?P<year>[0-9]{4})/' , views.year_archive),      re_path( 'article/(?P<article_id>[a-zA-Z0-9]+)/detail/' , views.detail_view),      re_path( 'articles/(?P<article_id>[a-zA-Z0-9]+)/edit/' , views.edit_view),      re_path( 'articles/(?P<article_id>[a-zA-Z0-9]+)/delete/' , views.delete_view), ] """ 1.函式 year_archive 中year引數是字串型別的 2.三個路由中article_id都是同樣的正則表示式,但是你需要寫三遍,當之後article_id規則改變後,需要同時修改三處程式碼, 在Django2.0中,可以使用 path 解決以上的兩個問題。 """ urlpatterns = [      path( 'articles/2003/' , views.special_case_2003),      path( 'articles/<int:year>/' , views.year_archive),      path( 'articles/<int:year>/<int:month>/' , views.month_archive),      path( 'articles/<int:year>/<int:month>/<slug>/' , views.article_detail), ]

2、基本規則

  • 使用尖括號(<>)從url中捕獲值。
  • 捕獲值中可以包含一個轉化器型別(converter type),比如使用 捕獲一個整數變數。若果沒有轉化器,將匹配任何字串,當然也包括了 / 字元。
  • 無需新增前導斜槓。

3、path轉化器

Django預設支援以下5個轉化器:

  • str,匹配除了路徑分隔符(/)之外的非空字串,這是預設的形式
  • int,匹配正整數,包含0。
  • slug,匹配字母、數字以及橫槓、下劃線組成的字串。
  • uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
  • path,匹配任何非空字串,包含了路徑分隔符

4、註冊自定義轉化器

對於一些複雜或者複用的需要,可以定義自己的轉化器。轉化器是一個類或介面,它的要求有三點:

  • regex 類屬性,字串型別
  • to_python(self, value) 方法,value是由類屬性 regex 所匹配到的字串,返回具體的Python變數值,以供Django傳遞到對應的檢視函式中。
  • to_url(self, value) 方法,和 to_python 相反,value是一個具體的Python變數值,返回其字串,通常用於url反向引用。
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # urls.py: from django.urls import register_converter, path from app01 import yearconvert,views   #使用register_converter 將其註冊到URL配置中: register_converter(yearconvert.FourDigitYearConverter, 'yyyy' )   urlpatterns = [      path( 'articles/<yyyy:year>/' , views.year_archive), ]   #app01.yearconvert.py: class FourDigitYearConverter:      regex = '[0-9]{4}'  #規則      def to_python( self , value):          return int (value) # 在這轉換了型別      def to_url( self , value):          return '%04d' % value   #app01.views.py: from django.shortcuts import render,HttpResponse,redirect def year_archive(request,year):      print (year, type (year))      return HttpResponse( 'ok' )

檢視

一個檢視函式,簡稱檢視,是一個簡單的Python 函式,它接受Web請求並且返回Web響應。響應可以是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文件,或者一張圖片. . . 是任何東西都可以。無論檢視本身包含什麼邏輯,都要返回響應。程式碼寫在哪裡也無所謂,只要它在你的Python目錄下面。除此之外沒有更多的要求了。為了將程式碼放在某處,約定是將檢視放置在專案或應用程式目錄中的名為views.py的檔案中。

一、HttpRequest物件

django將請求報文中的請求行、首部資訊、內容主體封裝成 HttpRequest 類中的屬性。

1.request屬性

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76