Python的WEB框架有Django、Tornado、Flask 等多種,Django相較與其餘WEB框架其優點爲:大而全,框架自己集成了ORM、模型綁定、模板引擎、緩存、Session等諸多功能。php
MVC介紹:html
M:model,模型,是應用程序中用於處理應用程序數據邏輯的部分,主要是負責對數據庫進行讀寫。前端
V:view,視圖,是應用程序中處理數據顯示的部分,一般視圖是依據模型中的數據建立的。python
C:controller,控制器,是應用程序處理與用戶交互的部分,一般控制器負責從視圖中去讀取數據,也向模型去發送數據。git
MTV與MVC二者區別與聯繫:web
MTV與MVC這兩種模式沒有根本上的區別,他們都是讓複雜的程序在各個組件之間保持鬆耦合關係,區別只是名字不一樣,叫法不一樣而已。正則表達式
MTV介紹:shell
M:Model(模型):負責業務對象與數據庫的對象(ORM)數據庫
T:Template(模版):負責如何把頁面展現給用戶django
V:View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
另外,Django還有一個url分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Template
注:本篇博客採用的是django2.0介紹
django簡易流程圖:
django簡單安裝配置
django #安裝: pip3 install django 添加環境變量 #1 建立project django-admin startproject mysite ---mysite ---settings.py ---url.py ---wsgi.py ---- manage.py(啓動文件) #2 建立APP python mannage.py startapp app01 #3 settings配置 TEMPLATES STATICFILES_DIRS=( os.path.join(BASE_DIR,"statics"), ) STATIC_URL = '/static/' # 咱們只能用 STATIC_URL,但STATIC_URL會按着你的STATICFILES_DIRS去找#4 根據需求設計代碼 url.py view.py #5 使用模版 render(req,"index.html") #6 啓動項目 python manage.py runserver 127.0.0.1:8090 #7 鏈接數據庫,操做數據 model.py
若是用pycharm能夠直接建的哦!
目錄詳細解釋:
若是用命令行建立,只會有如下幾個目錄:
django-admin.py startproject mysite
django-admin.py 是Django的一個用於管理任務的命令行工具,manage.py是對django-admin.py的簡單包裝,每個Django Project裏都會有一個mannage.py。
manage.py ----- Django項目裏面的工具,經過它能夠調用django shell和數據庫等。
settings.py ---- 包含了項目的默認設置,包括數據庫信息,調試標誌以及其餘一些工做的變量。
urls.py ----- 負責把URL模式映射到應用程序。
用python manage.py startapp app
運行python manage.py runserver 8000 或者直接用pycharm運行
此時,django已經安裝成功
如今咱們就寫一個例子:
mysite的urls:
from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('app01',include('app01.urls')), ]
app01的urls:
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
app01的views:
from django.shortcuts import render from django.http import HttpResponse def index(request): return HttpResponse("Hello, ylqh.")
訪問:
第一個簡易的django流程完成
URL配置(URLconf)就像Django 所支撐網站的目錄。是高質量Web應用程序中的一個重要細節,其實質就是經過url指到相應的視圖函數
Django可讓你設計URL,沒有.php
或沒有.cgi
要求。
url()函數能夠傳遞4個參數,其中2個是必須的:正則和view,以及2個可選的參數:kwargs和name
urlpatterns = [
path(正則表達式, views視圖函數,參數,別名),
]
參數說明:
1:正則表達式,它是一種匹配字符串或url地址的語法
2:一個可調對象,一般爲一個視圖函數或者一個指定視圖函數的字符串。若是是簡單捕獲,那麼捕獲的值將做爲一個位置參數進行傳遞,若是是命名捕獲,那麼將做爲一個關鍵字參數。
3:可選的任意數量的關鍵字參數能夠做爲一個字典傳遞給目標視圖。
4:可選的name參數,對你的URL進行命名,可讓你可以在Django的任意處,尤爲是模板內顯式地引用它。至關於給URL取了個全局變量名,你只須要修改這個全局變量的值,在整個Django中引用它的地方也將一樣得到改變
django1.x 系列:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^articles/2018/$', views.special_case_2018), #url(r'^articles/[0-9]{4}/$', views.year_archive), url(r'^articles/([0-9]{4})/$', views.year_archive), #no_named group url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
dgango2.0 系列:
urlpatterns = [ path('index/', views.index), path('articles/2018/', views.special_case_2018), path('articles/<int:year>/', views.year_archive), path('articles/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
注意:1:要從url中捕獲值,請使用尖括號:<>
2:捕獲的值能夠選擇包含轉換器類型。例如:<int : name> 捕獲整數參數。
3:沒有必要添加一個前斜槓,例如:articles 不是 /articles。
示例請求:
/articles/2018/03/
匹配列表中的第三個條目。Django會調用這個函數 。views.month_archive(request, year=2018,month=3)
/articles/2018/
會匹配列表中的第一個模式,而不是第二個模式,由於模式是按順序傳參的,而第一個模式是第一個要傳遞的參數。在這裏,Django會調用這個函數 views.special_case_2018(request)
/articles/2018/03/subao/
將匹配最終模式。Django會調用這個函數 。views.article_detail(request, year=2018, month=3, slug="subao")
2.路徑轉換器:
如下路徑轉換器默承認用:
str- 匹配任何非空字符串,不包括路徑分隔符'/'。默認的轉換器不包含在表達式中。 int - 匹配零或任何正整數。返回一個int值法、。 slug - 匹配由ASCII字母或數字組成的字符串,以及加上-字符和下劃線字符。例如:subao-yunwei-kaifa。 uuid - 匹配格式化的UUID。爲防止多個URL映射到同一頁面,必須包含破折號,而且字母必須是小寫。例如,075194d3-6885-417e-a8a8-6c931e272f00。返回一個 UUID實例。 path- 匹配任何非空字符串,包括路徑分隔符 '/'。這使您能夠匹配完整的URL路徑,而不只僅是URL路徑的一部分字符串。
自定義路徑轉換器
當默認的Path Converter不能知足需求時,Django2.0支持用戶註冊自定義的Path Converter。
Path Converter是一個類,定義Converter類須要包含下面的屬性或方法:
regex屬性,字符串類型。
to_python(self,value),它處理將匹配的字符串轉換成應該傳遞到視圖函數的類型。若是它不能轉換特定的值,則報ValueError。
to_url(self,value):和 to_python 相反,它會將Python類型轉換爲在URL中使用的字符串
示例:
app01/urls.py from django.urls import register_converter,path from app01 import views,converters urlpatterns = [ path('articles/<yyyy:year>/', views.year_yyyy), path('articles/<int:year>/', views.year_archive), ]
converters.py class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value
views.py def year_yyyy(request,year): return HttpResponse("hello yyyy" + str(year)) def year_archive(request,year): return HttpResponse("hello year" + str(year))
請求示例:
Django2.0也支持咱們使用正則表達式來捕獲值。注意,用正則表達式捕獲值,須要使用re_path(),而不是前面介紹的path()。
正則表達式建議使用命名正則表達式組,語法以下:
(?P<name>pattern)
尖括號裏的name爲分組名,pattern爲正則表達式。
前面的示例可使用正則表達式修改成:
from django.urls import path, re_path from . import views urlpatterns = [ path('articles/2018/', views.special_case_2018), re_path('articles/(?P<year>[0-9]{4})/', views.year_archive), re_path('articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.month_archive), re_path('articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-_]+)/', views.article_detail), ]
這裏與前面的例子的不一樣點:
1.這裏的代碼匹配更加嚴格,好比:year爲10001就沒法匹配,由於它超出了正則規定的4位數
2.傳給view函數的參數爲字符串類型,這點和 Django使用url 是同樣的
簡單介紹未命名的正則表達式組(這種方式不推薦使用!):
除了命名組的語法,例如:(?P<year>[0-9]{4}),相對應的未命名的語法:([0-9]{4})
請求的URL被看作是一個普通的Python字符串,URLconf在其上查找並匹配。進行匹配時將不包括GET或POST請求方式的參數以及域名。
例如,在https://www.example.com/myapp/
的請求中,URLconf將查找myapp/
。
在https://www.example.com/myapp/?page=3
的請求中,URLconf也將查找myapp/
。
URLconf不檢查使用何種HTTP請求方法,全部請求方法POST、GET、HEAD等都將路由到同一個URL的同一個視圖。在視圖中,才根據具體請求方法的不一樣,進行不一樣的處理。
一個小技巧是爲視圖的參數指定默認參數,例子:app01/urls.py
app01/urls.py from django.urls import register_converter,path,re_path from app01 import views,converters urlpatterns = [ path(r'blog', views.page), path(r'blog/page<int:num>/', views.page),#django2.0 url(r'^blog/page(?P<num>[0-9]+)/$', views.page),#django1.x ] views.py def page(request,num='1'): return HttpResponse('hello'+str(num))
在上面的例子中,兩個URL模式指向同一個視圖views.page
。可是第一個模式不會從URL中捕獲任何值。 若是第一個模式匹配,page()函數將使用num參數的默認值"1"。 若是第二個模式匹配,page()將使用捕獲的num值
當Django找不到與請求匹配的URL時,或者當拋出一個異常時,將調用一個錯誤處理視圖。錯誤視圖包括400、40三、404和500,分別表示請求錯誤、拒絕服務、頁面不存在和服務器錯誤。它們分別位於:
注意注意:這些值能夠在根URLconf中設置。在其它app01中的二級URLconf中設置這些變量無效
Django有內置的HTML模版,用於返回錯誤頁面給用戶,可是這些403,404頁面太難看了,一般咱們都自定義錯誤頁面。
首先,在根URLconf中額外增長下面的條目:
# URLconf from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/', views.page), url(r'^blog/page<int:num>/', views.page), ] # 增長的條目 handler400 = views.bad_request handler403 = views.permission_denied handler404 = views.page_not_found handler500 = views.page_error
而後在視圖中增長:
def page_not_found(request): return render(request, '404.html') def page_error(request): return render(request, '500.html') def permission_denied(request): return render(request, '403.html') def bad_request(request): return render(request, '400.html')
最後,你本身想要啥樣的錯誤頁面本身寫就ok了。
通常狀況,咱們會在每個app下面,各自建一個urls.py的路由模塊,而後從跟路由出發,將app所包含的url請求,所有轉發到相應的urls.py模塊中,
下面是django自己的URLconf的摘錄,它包含須要其餘的urlconf:
urlpatterns = [ # ... snip ... path('community/', include('aggregator.urls')), path('contact/', include('contact.urls')), # ... snip ... ]
注意:這個例子中的正則表達式不包含$(字符串結束的匹配符),可是包含一個末尾的斜槓,每當django遇到include()方法的時候,他會截斷與該點匹配的URL的部分,並將剩餘的字符串發送給include的URLconf以供進一步處理,也就是轉發到二級路由裏面去。
另一種轉發就是經過path()實例列表來包含url模式。如:
from django.urls import include, path from apps.main import views as main_views from credit import views as credit_views extra_patterns = [ path('reports/', credit_views.report), path('reports/<int:id>/', credit_views.report), path('charge/', credit_views.charge), ] urlpatterns = [ path('', main_views.homepage), path('help/', include('apps.help.urls')), path('credit/', include(extra_patterns)), ]
在這個例子中,/credit/reports/
URL將由credit_views.report()
Django視圖處理 。這種作法等同於把二級路由模塊內的代碼移動到了跟路由模塊裏面了,不過不推薦這種方式!
看下面的示例:
from django.urls import path from . import views urlpatterns = [ path('<page_slug>-<page_id>/history/', views.history), path('<page_slug>-<page_id>/edit/', views.edit), path('<page_slug>-<page_id>/discuss/', views.discuss), path('<page_slug>-<page_id>/permissions/', views.permissions), ]
上面的路由,前綴的URLconf中存在冗餘的現象,咱們能夠改進下,只需聲明共同的路徑(前綴)一次,並將後面的部分轉發:
from django.urls import include, path from . import views urlpatterns = [ path('<page_slug>-<page_id>/', include([ path('history/', views.history), path('edit/', views.edit), path('discuss/', views.discuss), path('permissions/', views.permissions), ])), ]
這樣看着就舒服多了。
正則表達容許嵌套參數,Django將解析他們而且把它們傳遞給視圖。當反轉查詢的時候,django將嘗試填充全部外部捕獲的參數,而忽略任何嵌套捕獲的參數,
考慮下面的URL模式,能夠選擇使用頁面參數
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 ]
以上兩種方式都是使用了嵌套參數,
# blog/page-1/ 將匹配page-1 並帶有兩個位置參數式page-1和1
# comments的模式將匹配page_number並帶有一個關鍵字參數是1(這一個例子中外圍參數是一個不捕獲的參數(?:...))
視圖須要最外層捕獲的參數來反查,在這個例子中是comments或者沒有參數,而能夠不帶參數或者用一個值來反查blog_articlespage-1/page_number
包含的URLconf從父URLconf接受捕獲的任何參數,官網示例:
# In settings/urls/main.py from django.urls import include, path urlpatterns = [ path('<username>/blog/', include('foo.urls.blog')), ] # In foo/urls/blog.py from django.urls import path from . import views urlpatterns = [ path('', views.blog.index), path('archive/', views.blog.archive), ] 本身示例: #mysite/urls.py from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('<username>/',include('app01.urls')) ] #app01/urls.py from django.urls import path from app01 import views urlpatterns = [ path('',views.index), path('archive',views.archive), ] #app01/views.py from django.http import HttpResponse def index(request,username): return HttpResponse("Hello, %s" % username) def archive(request,username): return HttpResponse("Hello, %s " % username)
上面的兩種url均可以捕獲到變量,並傳遞給urlconf,最終傳給視圖
URLconf具備一個鉤子(hook),容許你傳遞一個Python字典做爲額外的關鍵字參數給視圖函數
from django.urls import path from . import views urlpatterns = [ path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}), ]
在上面的例子中,對於/blog/2005/
請求,Django將調用views.year_archive(request, year='2005', foo='bar')
。理論上,你能夠在這個字典裏傳遞任何你想要的傳遞的東西。可是要注意,URL模式捕獲的命名關鍵字參數和在字典中傳遞的額外參數有可能具備相同的名稱,這會發生衝突,要避免。
#mysite/urls.py from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('app01/',include('app01.urls')), ] #app01/urls.py from django.urls import register_converter,path,re_path from app01 import views,converters urlpatterns = [ path('<int:year>/',views.year_archive,{'foo':'bar'}) ] #app01/views.py from django.http import HttpResponse def year_archive(request,year,foo='bar'): print(year,foo) return HttpResponse("hello year")
相似上面,也能夠傳遞額外的參數給include()。參數會傳遞給include指向的urlconf中的每一行
例如:下面的兩個URLconf在功能上是相同的:
第一:官網配置: # main.py from django.urls import include, path urlpatterns = [ path('blog/', include('inner'), {'blog_id': 3}), ] # inner.py from django.urls import path from mysite import views urlpatterns = [ path('archive/', views.archive), path('about/', views.about), ] 本身驗證: #mysite/urls.py from django.urls import include,path urlpatterns = [ path(r'blog/', include('app01.urls'),{'blog_id':3}), ] #app01/urls.py from django.urls import path from app01 import views urlpatterns = [ path('archive/',views.archive), path('about/',views.about), ] #app01/views.py from django.http import HttpResponse def archive(request,blog_id): return HttpResponse("Hello archive %s" % blog_id) def about(request,blog_id): return HttpResponse('hello about %s' % blog_id)
第二:
官網配置: # main.py from django.urls import include, path from mysite import views urlpatterns = [ path('blog/', include('inner')), ] # inner.py from django.urls import path urlpatterns = [ path('archive/', views.archive, {'blog_id': 3}), path('about/', views.about, {'blog_id': 3}), ] 本身驗證: #mysite/urls.py from django.urls import include,path urlpatterns = [ path(r'blog/', include('app01.urls')), ] #app01/urls.py from django.urls import path from app01 import views urlpatterns = [ path('archive/',views.archive,{'blog_id':3}), path('about/',views.about,{'blog_id':3}), ] #app01/views.py from django.http import HttpResponse def archive(request,blog_id): return HttpResponse("Hello archive %s" % blog_id) def about(request,blog_id): return HttpResponse('hello about %s' % blog_id)
注意,只有當你肯定被include的URLconf中的每一個視圖都接收你傳遞給它們的額外的參數時纔有意義,不然其中一個以上視圖不接收該參數都將致使錯誤異常。
可獲取URL的主要信息負責處理他的視圖的標識(例如名稱),其餘必須參與查找正確URL的信息,包括視圖參數的類型(位置,關鍵字)和值
django提供了一種解決方案,使得URL映射器是URL設計的惟一存儲庫,用URLconf提供它,能夠在兩個方向上使用:
1.從用戶/瀏覽器請求的URL開始,它調用正確的django視圖,提供它可能須要的任何參數以及從URL中提取的值,
2.從相應的django視圖的標識以及將傳遞給他的參數的值開始獲取管理的URL
第二種就是所謂的URL方向解析,方向URL匹配,方向URL查找或者僅僅URL反轉。
Django提供了用於執行URL反轉的工具,以匹配須要URL的不一樣層:
1.在模板中:使用URL模板標籤。(也就是寫前端網頁時)
2.在python代碼中:使用reverse()
函數。(也就是views中)
3.在更高層的與處理Django模型實例相關的代碼中:使用get_absolute_url()
方法。(也就是在模型model中)
例子:URLconf
from django.urls import path from . import views urlpatterns = [ #... path('articles/<int:year>/', views.year_archive, name='news-year-archive'), #... ]
根據這個設計,對應與年份nnnn的檔案URL是/articles/nnnn
您可使用下面的方式在模板中得到這些內容:
<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>
或者在python代碼中:
from django.urls import reverse from django.http import HttpResponseRedirect def redirect_to_year(request): # ... year = 2006 # ... return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
若是出於某種緣由決定應該更改每一年發佈文章內容的URL,那麼您只須要更改URLconf中的條目。
在某種狀況下,視圖是具備通用性的,所以URL和視圖之間可能存在多對一的關係,對於這些狀況,視圖名稱在倒轉URL時不是一個足夠好的標識符。見下面的命名URL模式
URL模式:
#mysite/urls.py from django.urls import include,path urlpatterns = [ path(r'blog/', include('app01.urls')), ] #app01/urls.py from django.urls import path from app01 import views urlpatterns = [ path('art/',views.art,name='app01-art'), ] #app01/views.py from django.shortcuts import render def art(request): return render(request,'art.html',{"day":"abc"}) #art.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ day }}</h1> <a href="{% url 'app01-art' %}">點擊</a> </body> </html>
視圖:在視圖函數中調用url,使用reverse('別名')
####urls from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^art/', views.art3, name='app01-art'), ] ####views def art3(request): print(reverse('app01-art')) #在視圖函數中對url進行反向解析 return HttpResponse("OK")
URL命名空間能夠保證反查到惟一的URL,即便不一樣的app使用相同的URL名稱。
第三方應用始終使用帶命名空間的URL是一個很好的作法。
相似地,它還容許你在一個應用有多個實例部署的狀況下反查URL。 換句話講,由於一個應用的多個實例共享相同的命名URL,命名空間提供了一種區分這些命名URL 的方法。
實現命名空間的作法很簡單,在urlconf文件中添加app_name = 'polls'
和namespace='author-polls'
這種相似的定義
例子:
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'), ... ]
視圖中的調用方法:
reverse('polls:index', current_app=self.request.resolver_match.namespace)
模板中:
{% url 'polls:index' %}