一、創建Django
項目:
用命令行創建:
創建項目:在終端通過命令:django-admin startproject [項目名稱]
即可創建,比如:django-admin startproject fisher_django
創建應用:在終端進入到項目所在的路徑,然后執行python manage.py startapp [app名稱] 即可
創建一個app
用pycharm創建
:
pycharm
創建項目后,需重新進入到命令行創建app
project和app的關系:
app是django項目的組成部分,一個app代表項目中的一個模塊,所有URL請求的響應都是由app來處理
django項目由多個app組成,一個app可以被用到其他項目
項目結構介紹:
manage.py:和項目交互的文件,python manage.py [子命令],可通過python manage.py help查看幫助
settings.py:項目的設置項
urls.py:配置URL路由
wsgi.py:項目與WSGI協議兼容的web服務器入口,用於項目部署
運行Django項目:
python manage.py runserver,
默認端口8000
指定端口號python manage.py runserver 9000
若
需在其它電腦訪問本站,python manage.py runserver 0.0.0.0:8000
也可通過pycharm
運行
二、視圖與URL分發器
URL分發器
視圖:
視圖一般都寫在app
的views.py
中。並且視圖的第一個參數永遠都是request
(一個HttpRequest)對象。這個對象存儲了請求過來的所有信息,包括攜帶的參數以及一些頭部信息等。在視圖中,一般是完成邏輯相關的操作。比如這個請求是添加一篇博客,那么可以通過request來接收到這些數據,然后存儲到數據庫中,最后再把執行的結果返回給瀏覽器。視圖函數的返回結果必須是HttpResponseBase
對象或者子類的對象。示例代碼如下:
from django.http import HttpResponse def book_list(request): return HttpResponse("書籍列表!")
URL映射:
視圖寫完后,要與URL進行映射,也即用戶在瀏覽器中輸入什么url
的時候可以請求到這個視圖函數。在用戶輸入了某個url
,請求到我們的網站的時候,django
會從項目的urls.py
文件中尋找對應的視圖。在urls.py
文件中有一個urlpatterns
變量,以后django
就會從這個變量中讀取所有的匹配規則。匹配規則需要使用django.urls.path
函數進行包裹,這個函數會根據傳入的參數返回URLPattern
或者是URLResolver
的對象。示例代碼如下:
from django.contrib import admin from django.urls import path from book import views urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list) ]
URL中添加參數:
有時候,url
中包含了一些參數需要動態調整。比如簡書某篇文章的詳情頁的url,是https://www.jianshu.com/p/a5aab9c4978e
后面的a5aab9c4978e
就是這篇文章的id
,那么簡書的文章詳情頁面的url就可以寫成https://www.jianshu.com/p/<id>
,其中id就是文章的id。那么如何在django
中實現這種需求呢。這時候我們可以在path
函數中,使用尖括號的形式來定義一個參數。比如我現在想要獲取一本書籍的詳細信息,那么應該在url
中指定這個參數。示例代碼如下:
from django.contrib import admin from django.urls import path from book import views urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list), path('book/<book_id>/',views.book_detail) ]
而views.py
中的代碼如下:
def book_detail(request,book_id): text = "您輸入的書籍的id是:%s" % book_id return HttpResponse(text)
當然,也可以通過查詢字符串的方式傳遞一個參數過去。示例代碼如下:
urlpatterns = [
path('admin/', admin.site.urls), path('book/',views.book_list), path('book/detail/',views.book_detail) ]
在views.py
中的代碼如下:
def book_detail(request): book_id = request.GET.get("id") text = "您輸入的書籍id是:%s" % book_id return HttpResponse(text)
以后在訪問的時候就是通過/book/detail/?id=1
即可將參數傳遞過去。
URL中包含另外一個urls模塊:
在我們的項目中,不可能只有一個app
,如果把所有的app
的views
中的視圖都放在urls.py
中進行映射,肯定會讓代碼顯得非常亂。因此django
給我們提供了一個方法,可以在app
內部包含自己的url
匹配規則,而在項目的urls.py
中再統一包含這個app
的urls
。使用這個技術需要借助include
函數。示例代碼如下:
# first_project/urls.py文件: from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('book/',include("book.urls")) ]
在urls.py
文件中把所有的和book
這個app
相關的url
都移動到app/urls.py
中了,然后在first_project/urls.py
中,通過include
函數包含book.urls
,以后在請求book
相關的url的時候都需要加一個book
的前綴。
# book/urls.py文件: from django.urls import path from . import views urlpatterns = [ path('list/',views.book_list), path('detail/<book_id>/',views.book_detail) ]
以后訪問書的列表的url
的時候,就通過/book/list/
來訪問,訪問書籍詳情頁面的url
的時候就通過book/detail/<id>
來訪問。
path函數:
path
函數的定義為:path(route,view,name=None,kwargs=None)
。以下對這幾個參數進行講解。
-
route
參數:url
的匹配規則。這個參數中可以指定url
中需要傳遞的參數,比如在訪問文章詳情頁的時候,可以傳遞一個id
。傳遞參數是通過<>
尖括號來進行指定的。並且在傳遞參數的時候,可以指定這個參數的數據類型,比如文章的id
都是int
類型,那么可以這樣寫<int:id>
,以后匹配的時候,就只會匹配到id
為int
類型的url
,而不會匹配其他的url
,並且在視圖函數中獲取這個參數的時候,就已經被轉換成一個int
類型了。其中還有幾種常用的類型:- str:非空的字符串類型。默認的轉換器。但是不能包含斜杠。
- int:匹配任意的零或者正數的整形。到視圖函數中就是一個int類型。
- slug:由英文中的橫杠
-
,或者下划線_
連接英文字符或者數字而成的字符串。 - uuid:匹配
uuid
字符串。 - path:匹配非空的英文字符串,可以包含斜杠。
-
view
參數:可以為一個視圖函數或者是類視圖.as_view()
或者是django.urls.include()
函數的返回值。 -
name
參數:這個參數是給這個url
取個名字的,這在項目比較大,url
比較多的時候用處很大。 -
kwargs
參數:有時候想給視圖函數傳遞一些額外的參數,就可以通過kwargs
參數進行傳遞。這個參數接收一個字典。傳到視圖函數中的時候,會作為一個關鍵字參數傳過去。比如以下的url
規則:from django.urls import path from . import views urlpatterns = [ path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}), ]
那么以后在訪問
blog/1991/
這個url的時候,會將foo=bar
作為關鍵字參數傳給year_archive
函數。
re_path函數:
有時候我們在寫url匹配的時候,想要寫使用正則表達式來實現一些復雜的需求,那么這時候我們可以使用re_path
來實現。re_path
的參數和path
參數一模一樣,只不過第一個參數也就是route
參數可以為一個正則表達式。
一些使用re_path
的示例代碼如下:
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), ]
以上例子中我們可以看到,所有的route
字符串前面都加了一個r
,表示這個字符串是一個原生字符串。在寫正則表達式中是推薦使用原生字符串的,這樣可以避免在python
這一層面進行轉義。而且,使用正則表達式捕獲參數的時候,是用一個圓括號進行包裹,然后這個參數的名字是通過尖括號<year>
進行包裹,之后才是寫正則表達式的語法。
include函數:
在項目變大以后,經常不會把所有的url
匹配規則都放在項目的urls.py
文件中,而是每個app
都有自己的urls.py
文件,在這個文件中存儲的都是當前這個app
的所有url
匹配規則。然后再統一注冊到項目的urls.py
文件中。include
函數有多種用法,這里講下兩種常用的用法。
-
include(pattern,namespace=None)
:直接把其他app
的urls
包含進來。示例代碼如下:from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('book/',include("book.urls")) ]
當然也可以傳遞
namespace
參數來指定一個實例命名空間,但是在使用實例命名空間之前,必須先指定一個應用命名空間。示例代碼如下:# 主urls.py文件: from django.urls import path,include urlpatterns = [ path('movie/',include('movie.urls',namespace='movie')) ]
然后在
movie/urls.py
中指定應用命名空間。實例代碼如下:from django.urls import path from . import views # 應用命名空間 app_name = 'movie' urlpatterns = [ path('',views.movie,name='index'), path('list/',views.movie_list,name='list'), ]
-
include(pattern_list)
:可以包含一個列表或者一個元組,這個元組或者列表中又包含的是path
或者是re_path
函數。 -
include((pattern,app_namespace),namespace=None)
:在包含某個app
的urls
的時候,可以指定命名空間,這樣做的目的是為了防止不同的app
下出現相同的url
,這時候就可以通過命名空間進行區分。示例代碼如下:from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('book/',include(("book.urls",'book')),namespace='book') ]
但是這樣做的前提是已經包含了應用命名空間。即在
myapp.urls.py
中添加一個和urlpatterns
同級別的變量app_name
。
指定默認的參數:
使用path
或者是re_path
的后,在route
中都可以包含參數,而有時候想指定默認的參數,這時候可以通過以下方式來完成。示例代碼如下:
from django.urls import path from . import views urlpatterns = [ path('blog/', views.page), path('blog/page<int:num>/', views.page), ] # View (in blog/views.py) def page(request, num=1): # Output the appropriate page of blog entries, according to num. ...
當在訪問blog/
的時候,因為沒有傳遞num
參數,所以會匹配到第一個url,這時候就執行view.page
這個視圖函數,而在page
函數中,又有num=1
這個默認參數。因此這時候就可以不用傳遞參數。而如果訪問blog/1
的時候,因為在傳遞參數的時候傳遞了num
,因此會匹配到第二個url
,這時候也會執行views.page
,然后把傳遞進來的參數傳給page
函數中的num
。
url反轉:
之前我們都是通過url來訪問視圖函數。有時候我們知道這個視圖函數,但是想反轉回他的url。這時候就可以通過reverse
來實現。示例代碼如下:
reverse("list") > /book/list/
如果有應用命名空間或者有實例命名空間,那么應該在反轉的時候加上命名空間。示例代碼如下:
reverse('book:list') > /book/list/
如果這個url中需要傳遞參數,那么可以通過kwargs
來傳遞參數。示例代碼如下:
reverse("book:detail",kwargs={"book_id":1}) > /book/detail/1
因為django
中的reverse
反轉url
的時候不區分GET
請求和POST
請求,因此不能在反轉的時候添加查詢字符串的參數。如果想要添加查詢字符串的參數,只能手動的添加。示例代碼如下:
login_url = reverse('login') + "?next=/"
自定義URL轉換器:
之前已經學到過一些django內置的url
轉換器,包括有int
、uuid
等。有時候這些內置的url轉換器
並不能滿足我們的需求,因此django給我們提供了一個接口可以讓我們自己定義自己的url轉換器。
自定義url
轉換器按照以下五個步驟來走就可以了:
- 定義一個類。
- 在類中定義一個屬性
regex
,這個屬性是用來保存url
轉換器規則的正則表達式。 - 實現
to_python(self,value)
方法,這個方法是將url
中的值轉換一下,然后傳給視圖函數的。 - 實現
to_url(self,value)
方法,這個方法是在做url
反轉的時候,將傳進來的參數轉換后拼接成一個正確的url。 - 將定義好的轉換器,注冊到django中。
比如寫一個匹配四個數字年份的url
轉換器。示例代碼如下:
# 1. 定義一個類 class FourDigitYearConverter: # 2. 定義一個正則表達式 regex = '[0-9]{4}' # 3. 定義to_python方法 def to_python(self, value): return int(value) # 4. 定義to_url方法 def to_url(self, value): return '%04d' % value # 5. 注冊到django中 from django.urls import register_converter register_converter(converters.FourDigitYearConverter, 'yyyy') urlpatterns = [ path('articles/2003/', views.special_case_2003), # 使用注冊的轉換器 path('articles/<yyyy:year>/', views.year_archive), ... ]