python之路,西游之路——python全棧——Django的web框架本質

 2023-10-08 阅读 46 评论 0

摘要:知識預覽 Django基本命令二 路由配置系統(URLconf)三 編寫視圖四 Template五 數據庫與ORMadmin的配置 一 什么是web框架? 框架,即framework,特指為解決一個開放性問題而設計的具有一定約束性的支撐結構,使用框架可以幫你快速開發特

知識預覽

  • Django基本命令
  • 二 路由配置系統(URLconf)
  • 三 編寫視圖
  • 四 Template
  • 五 數據庫與ORM
  • admin的配置

一 什么是web框架?

框架,即framework,特指為解決一個開放性問題而設計的具有一定約束性的支撐結構,使用框架可以幫你快速開發特定的系統,簡單地說,就是你用別人搭建好的舞臺來做表演。

對于所有的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。

?View Code

????? 最簡單的Web應用就是先把HTML用文件保存好,用一個現成的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。

如果要動態生成HTML,就需要把上述步驟自己來實現。不過,接受HTTP請求、解析HTTP請求、發送HTTP響應都是苦力活,如果我們自己來寫這些底層代碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規范。

python之路。????? 正確的做法是底層代碼由專門的服務器軟件實現,我們用Python專注于生成HTML文檔。因為我們不希望接觸到TCP連接、HTTP原始請求和響應格式,所以,需要一個統一的接口,讓我們專心用Python編寫Web業務。

這個接口就是WSGI:Web Server Gateway Interface。

-----------------------------Do a web? framework ourselves---------------------------

step 1:

 1 from wsgiref.simple_server import make_server
 2 
 3 
 4 def application(environ, start_response):
 5     start_response('200 OK', [('Content-Type', 'text/html')])
 6     return [b'<h1>Hello, web!</h1>']
 7 
 8 
 9 httpd = make_server('', 8080, application)
10 
11 print('Serving HTTP on port 8000...')
12 # 開始監聽HTTP請求:
13 httpd.serve_forever()
View Code

注意:

 1 整個application()函數本身沒有涉及到任何解析HTTP的部分,也就是說,底層代碼不需要我們自己編寫,
 2 我們只負責在更高層次上考慮如何響應請求就可以了。
 3 
 4 application()函數必須由WSGI服務器來調用。有很多符合WSGI規范的服務器,我們可以挑選一個來用。
 5 
 6 Python內置了一個WSGI服務器,這個模塊叫wsgiref    
 7     
 8     
 9 application()函數就是符合WSGI標準的一個HTTP處理函數,它接收兩個參數:
10 
11         //environ:一個包含所有HTTP請求信息的dict對象;
12         
13         //start_response:一個發送HTTP響應的函數。
14 
15 在application()函數中,調用:
16 
17 start_response('200 OK', [('Content-Type', 'text/html')])
18 
19 就發送了HTTP響應的Header,注意Header只能發送一次,也就是只能調用一次start_response()函數。
20 start_response()函數接收兩個參數,一個是HTTP響應碼,一個是一組list表示的HTTP Header,每
21 個Header用一個包含兩個str的tuple表示。
22 
23 通常情況下,都應該把Content-Type頭發送給瀏覽器。其他很多常用的HTTP Header也應該發送。
24 
25 然后,函數的返回值b'<h1>Hello, web!</h1>'將作為HTTP響應的Body發送給瀏覽器。
26 
27 有了WSGI,我們關心的就是如何從environ這個dict對象拿到HTTP請求信息,然后構造HTML,
28 通過start_response()發送Header,最后返回Body。
View Code

step 2

 1 print(environ['PATH_INFO'])
 2     path=environ['PATH_INFO']
 3     start_response('200 OK', [('Content-Type', 'text/html')])
 4     f1=open("index1.html","rb")
 5     data1=f1.read()
 6     f2=open("index2.html","rb")
 7     data2=f2.read()
 8 
 9     if path=="/yuan":
10         return [data1]
11     elif path=="/alex":
12         return [data2]
13     else:
14         return ["<h1>404</h1>".encode('utf8')]
View Code

step3

 1 from wsgiref.simple_server import make_server
 2 
 3 def f1():
 4     f1=open("index1.html","rb")
 5     data1=f1.read()
 6     return [data1]
 7 
 8 def f2():
 9     f2=open("index2.html","rb")
10     data2=f2.read()
11     return [data2]
12 
13 def application(environ, start_response):
14 
15     print(environ['PATH_INFO'])
16     path=environ['PATH_INFO']
17     start_response('200 OK', [('Content-Type', 'text/html')])
18 
19 
20     if path=="/yuan":
21         return f1()
22 
23     elif path=="/alex":
24         return f2()
25 
26     else:
27         return ["<h1>404</h1>".encode("utf8")]
28 
29 
30 httpd = make_server('', 8502, application)
31 
32 print('Serving HTTP on port 8084...')
33 
34 # 開始監聽HTTP請求:
35 httpd.serve_forever()
View Code

step4

 1 from wsgiref.simple_server import make_server
 2 
 3 
 4 def f1(req):
 5     print(req)
 6     print(req["QUERY_STRING"])
 7 
 8     f1=open("index1.html","rb")
 9     data1=f1.read()
10     return [data1]
11 
12 def f2(req):
13 
14     f2=open("index2.html","rb")
15     data2=f2.read()
16     return [data2]
17 
18 import time
19 
20 def f3(req):        #模版以及數據庫
21 
22     f3=open("index3.html","rb")
23     data3=f3.read()
24     times=time.strftime("%Y-%m-%d %X", time.localtime())
25     data3=str(data3,"utf8").replace("!time!",str(times))
26 
27 
28     return [data3.encode("utf8")]
29 
30 
31 def routers():
32 
33     urlpatterns = (
34         ('/yuan',f1),
35         ('/alex',f2),
36         ("/cur_time",f3)
37     )
38     return urlpatterns
39 
40 
41 def application(environ, start_response):
42 
43     print(environ['PATH_INFO'])
44     path=environ['PATH_INFO']
45     start_response('200 OK', [('Content-Type', 'text/html')])
46 
47 
48     urlpatterns = routers()
49     func = None
50     for item in urlpatterns:
51         if item[0] == path:
52             func = item[1]
53             break
54     if func:
55         return func(environ)
56     else:
57         return ["<h1>404</h1>".encode("utf8")]
58 
59 httpd = make_server('', 8518, application)
60 
61 print('Serving HTTP on port 8084...')
62 
63 # 開始監聽HTTP請求:
64 
65 httpd.serve_forever()
View Code

伙計們,不知不覺我們自己已經寫出一個web框架啦!

二 MVC和MTV模式

Python 框架、著名的MVC模式:所謂MVC就是把web應用分為模型(M),控制器(C),視圖(V)三層;他們之間以一種插件似的,松耦合的方式連接在一起。

模型負責業務對象與數據庫的對象(ORM),視圖負責與用戶的交互(頁面),控制器(C)接受用戶的輸入調用模型和視圖完成用戶的請求。

???????????????????

Django的MTV模式本質上與MVC模式沒有什么差別,也是各組件之間為了保持松耦合關系,只是定義上有些許不同,Django的MTV分別代表:

? ? ? ?Model(模型):負責業務對象與數據庫的對象(ORM)

python 前端,? ? ? ?Template(模版):負責如何把頁面展示給用戶

? ? ? ?View(視圖):負責業務邏輯,并在適當的時候調用Model和Template

? ? ? ?此外,Django還有一個url分發器,它的作用是將一個個URL的頁面請求分發給不同的view處理,view再調用相應的Model和Template

?三 django的流程和命令行工具

django實現流程

 1 django
 2     #安裝: pip3 install django
 3 
 4           添加環境變量
 5 
 6     #1  創建project
 7        django-admin startproject mysite
 8 
 9        ---mysite
10 
11           ---settings.py
12           ---url.py
13           ---wsgi.py
14 
15        ---- manage.py(啟動文件)  
16 
17     #2  創建APP       
18        python mannage.py startapp  app01
19 
20     #3  settings配置
21     
22        TEMPLATES
23 
24        STATICFILES_DIRS=(
25             os.path.join(BASE_DIR,"statics"),
26         )
27 
28        STATIC_URL = '/static/' 
29        #  我們只能用 STATIC_URL,但STATIC_URL會按著你的STATICFILES_DIRS去找#4  根據需求設計代碼
30            url.py
31            view.py
32 
33     #5  使用模版
34        render(req,"index.html")   
35 
36     #6  啟動項目
37        python manage.py runserver  127.0.0.1:8090
38 
39     #7  連接數據庫,操作數據
40        model.py
View Code

django的命令行工具

django-admin.py 是Django的一個用于管理任務的命令行工具,manage.py是對django-admin.py的簡單包裝,每一個Django Project里都會有一個mannage.py。

python web。<1> 創建一個django工程 : django-admin.py startproject mysite

? ? ??? 當前目錄下會生成mysite的工程,目錄結構如下:

? ? ????

  • manage.py?-----?Django項目里面的工具,通過它可以調用django?shell和數據庫等。
  • settings.py?----?包含了項目的默認設置,包括數據庫信息,調試標志以及其他一些工作的變量。
  • urls.py?-----?負責把URL模式映射到應用程序。

<2>在mysite目錄下創建blog應用:?python manage.py startapp blog

? ? ????

python編程?<3>啟動django項目:python manage.py runserver 8080

? ? ? ?這樣我們的django就啟動起來了!當我們訪問:http://127.0.0.1:8080/時就可以看到:

? ? ? ?

<4>生成同步數據庫的腳本:python?manage.py?makemigrations ?

? ? ? ? ? ? ? ? ?????同步數據庫: ?python?manage.py?migrate ??

qpython、? ? ? ?注意:在開發過程中,數據庫同步誤操作之后,難免會遇到后面不能同步成功的情況,解決這個問題的一個簡單粗暴方法是把migrations目錄下

? ? ? ? ? ? ? ??的腳本(除__init__.py之外)全部刪掉,再把數據庫刪掉之后創建一個新的數據庫,數據庫同步操作再重新做一遍。 ???????????

<5>當我們訪問http://127.0.0.1:8080/admin/時,會出現:

? ? ? ?

? ? ? ?所以我們需要為進入這個項目的后臺創建超級管理員:python?manage.py?createsuperuser設置好用戶名和密碼后便可登錄啦!

java和python、<6>清空數據庫:python?manage.py? flush

<7>查詢某個命令的詳細信息: django-admin.py ?help? startapp

? ? ? ?admin?是Django?自帶的一個后臺數據庫管理系統。

<8>啟動交互界面 :python?manage.py??shell

? ???這個命令和直接運行 python 進入 shell 的區別是:你可以在這個 shell 里面調用當前項目的 models.py 中的 API,對于操作數據,還有一些小測試非常方便。

python 后端?<9>?終端上輸入python?manage.py?可以看到詳細的列表,在忘記子名稱的時候特別有用

實例練習1-提交數據并展示

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <h1>創建個人信息</h1>
 9 
10 <form action="/userInfor/" method="post">
11 
12     <p>姓名<input type="text" name="username"></p>
13     <p>性別<input type="text" name="sex"></p>
14     <p>郵箱<input type="text" name="email"></p>
15     <p><input type="submit" value="submit"></p>
16 
17 </form>
18 
19 <hr>
20 
21 <h1>信息展示</h1>
22 
23 <table border="1">
24 
25     <tr>
26         <td>姓名</td>
27         <td>性別</td>
28         <td>郵箱</td>
29     </tr>
30     {% for i in info_list %}
31 
32         <tr>
33             <td>{{ i.username }}</td>
34             <td>{{ i.sex }}</td>
35             <td>{{ i.email }}</td>
36         </tr>
37 
38     {% endfor %}
39 
40 </table>
41 
42 </body>
43 </html>
44 
45 
46 -----------------------url.py---------------------------------------
47 url(r'^userInfor/', views.userInfor)
48 
49 -----------------------views.py--------------------------------------
50 
51 info_list=[]
52 
53 def userInfor(req):
54 
55     if req.method=="POST":
56         username=req.POST.get("username",None)
57         sex=req.POST.get("sex",None)
58         email=req.POST.get("email",None)
59 
60         info={"username":username,"sex":sex,"email":email}
61         info_list.append(info)
62 
63     return render(req,"userInfor.html",{"info_list":info_list})
View Code

實例練習2-提交數據并展示(數據庫)

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <h1>創建個人信息</h1>
 9 
10 <form action="/userInfor/" method="post">
11 
12     <p>姓名<input type="text" name="username"></p>
13     <p>性別<input type="text" name="sex"></p>
14     <p>郵箱<input type="text" name="email"></p>
15     <p><input type="submit" value="submit"></p>
16 
17 </form>
18 
19 <hr>
20 
21 <h1>信息展示</h1>
22 
23 <table border="1">
24 
25     <tr>
26         <td>姓名</td>
27         <td>性別</td>
28         <td>郵箱</td>
29     </tr>
30     {% for i in info_list %}
31 
32         <tr>
33             <td>{{ i.username }}</td>
34             <td>{{ i.sex }}</td>
35             <td>{{ i.email }}</td>
36         </tr>
37 
38     {% endfor %}
39 
40 </table>
41 
42 </body>
43 </html>
44 
45 
46 ----------------------------------------------models.py
47 from django.db import models
48 
49 # Create your models here.
50 
51 
52 class UserInfor(models.Model):
53 
54     username=models.CharField(max_length=64)
55     sex=models.CharField(max_length=64)
56     email=models.CharField(max_length=64)
57 
58 ----------------------------------------------views.py
59 
60 from django.shortcuts import render
61 
62 from app01 import models
63 # Create your views here.
64 
65 
66 def userInfor(req):
67 
68     if req.method=="POST":
69         u=req.POST.get("username",None)
70         s=req.POST.get("sex",None)
71         e=req.POST.get("email",None)
72 
73 
74        #---------表中插入數據方式一
75             # info={"username":u,"sex":e,"email":e}
76             # models.UserInfor.objects.create(**info)
77 
78        #---------表中插入數據方式二
79         models.UserInfor.objects.create(
80             username=u,
81             sex=s,
82             email=e
83         )
84 
85         info_list=models.UserInfor.objects.all()
86 
87         return render(req,"userInfor.html",{"info_list":info_list})
88 
89     return render(req,"userInfor.html")
View Code

四 Django的配置文件(settings)

靜態文件設置:

  1 一、概述:
  2 
  3      #靜態文件交由Web服務器處理,Django本身不處理靜態文件。簡單的處理邏輯如下(以nginx為例):
  4 
  5      #          URI請求-----> 按照Web服務器里面的配置規則先處理,以nginx為例,主要求配置在nginx.
  6                              #conf里的location
  7 
  8                          |---------->如果是靜態文件,則由nginx直接處理
  9 
 10                          |---------->如果不是則交由Django處理,Django根據urls.py里面的規則進行匹配
 11 
 12     # 以上是部署到Web服務器后的處理方式,為了便于開發,Django提供了在開發環境的對靜態文件的處理機制,方法是這樣:
 13 
 14     #1、在INSTALLED_APPS里面加入'django.contrib.staticfiles',
 15 
 16     #2、在urls.py里面加入
 17        if settings.DEBUG:  
 18            urlpatterns += patterns('', url(r'^media/(?P<path>.*)$', 
 19            'django.views.static.serve', {'document_root': settings.MEDIA_ROOT }),   
 20             url(r'^static/(?P<path>.*)$',
 21           'django.views.static.serve',{'document_root':settings.STATIC_ROOT}), )  
 22 
 23     # 3、這樣就可以在開發階段直接使用靜態文件了。
 24 
 25 二、MEDIA_ROOT和MEDIA_URL
 26 
 27         #而靜態文件的處理又包括STATIC和MEDIA兩類,這往往容易混淆,在Django里面是這樣定義的:
 28 
 29         #MEDIA:指用戶上傳的文件,比如在Model里面的FileFIeld,ImageField上傳的文件。如果你定義
 30 
 31         #MEDIA_ROOT=c:\temp\media,那么File=models.FileField(upload_to="abc/")#,上傳的文件就會被保存到c:\temp\media\abc  
 32         #eg:
 33             class blog(models.Model):  
 34                    Title=models.charField(max_length=64)  
 35                    Photo=models.ImageField(upload_to="photo") 
 36         #     上傳的圖片就上傳到c:\temp\media\photo,而在模板中要顯示該文件,則在這樣寫
 37         #在settings里面設置的MEDIA_ROOT必須是本地路徑的絕對路徑,一般是這樣寫:
 38                  BASE_DIR= os.path.abspath(os.path.dirname(__file__))  
 39                  MEDIA_ROOT=os.path.join(BASE_DIR,'media/').replace('\\','/') 
 40 
 41         #MEDIA_URL是指從瀏覽器訪問時的地址前綴,舉個例子:
 42             MEDIA_ROOT=c:\temp\media\photo  
 43             MEDIA_URL="/data/"
 44         #在開發階段,media的處理由django處理:
 45 
 46         #    訪問http://localhost/data/abc/a.png就是訪問c:\temp\media\photo\abc\a.png
 47 
 48         #    在模板里面這樣寫<img src="{{MEDIA_URL}}abc/a.png">
 49 
 50         #    在部署階段最大的不同在于你必須讓web服務器來處理media文件,因此你必須在web服務器中配置,
 51         #  以便能讓web服務器能訪問media文件
 52         #    以nginx為例,可以在nginx.conf里面這樣:
 53 
 54                  location ~/media/{
 55                        root/temp/
 56                        break;
 57                     }
 58 
 59         #    具體可以參考如何在nginx部署django的資料。
 60 
 61 三、STATIC_ROOT和STATIC_URL、
 62     STATIC主要指的是如css,js,images這樣文件,在settings里面可以配置STATIC_ROOT和STATIC_URL,
 63     配置方式與MEDIA_ROOT是一樣的,但是要注意
 64 
 65     #STATIC文件一般保存在以下位置:
 66 
 67     #1、STATIC_ROOT:在settings里面設置,一般用來放一些公共的js,css,images等。
 68 
 69     #2、app的static文件夾,在每個app所在文夾均可以建立一個static文件夾,然后當運行collectstatic時,
 70     #    Django會遍歷INSTALL_APPS里面所有app的static文件夾,將里面所有的文件復制到STATIC_ROOT。因此,
 71     #   如果你要建立可復用的app,那么你要將該app所需要的靜態文件放在static文件夾中。
 72 
 73     # 也就是說一個項目引用了很多app,那么這個項目所需要的css,images等靜態文件是分散在各個app的static文件的,比
 74     #  較典型的是admin應用。當你要發布時,需要將這些分散的static文件收集到一個地方就是STATIC_ROOT。
 75 
 76     #3、STATIC文件還可以配置STATICFILES_DIRS,指定額外的靜態文件存儲位置。
 77     #  STATIC_URL的含義與MEDIA_URL類似。
 78 
 79     # ----------------------------------------------------------------------------
 80     #注意1:
 81         #為了后端的更改不會影響前端的引入,避免造成前端大量修改
 82 
 83         STATIC_URL = '/static/'               #引用名
 84         STATICFILES_DIRS = (
 85             os.path.join(BASE_DIR,"statics")  #實際名 ,即實際文件夾的名字
 86         )
 87 
 88         #django對引用名和實際名進行映射,引用時,只能按照引用名來,不能按實際名去找
 89         #<script src="/statics/jquery-3.1.1.js"></script>
 90         #------error-----不能直接用,必須用STATIC_URL = '/static/':
 91         #<script src="/static/jquery-3.1.1.js"></script>
 92 
 93     #注意2(statics文件夾寫在不同的app下,靜態文件的調用):
 94 
 95         STATIC_URL = '/static/'
 96 
 97         STATICFILES_DIRS=(
 98             ('hello',os.path.join(BASE_DIR,"app01","statics")) ,
 99         )
100 
101         #<script src="/static/hello/jquery-1.8.2.min.js"></script>
102 
103     #注意3:
104         STATIC_URL = '/static/'
105         {% load staticfiles %}
106        # <script src={% static "jquery-1.8.2.min.js" %}></script>
View Code

其它重要參數設置:

APPEND_SLASHDefault: TrueWhen set to True, if the request URL does not match any of the patterns in the URLconf and it 
doesn’t end in a slash, an HTTP redirect is issued to the same URL with a slash appended. Note
that the redirect may cause any data submitted in a POST request to be lost.

五 Django URL (路由系統)

???? URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL模式以及要為該URL模式調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對于這個URL調用這段代碼,對于那個URL調用那段代碼。

1
2
3
urlpatterns = [
????url(正則表達式, views視圖函數,參數,別名),
]

參數說明:

  • 一個正則表達式字符串
  • 一個可調用對象,通常為一個視圖函數或一個指定視圖函數路徑的字符串
  • 可選的要傳遞給視圖函數的默認參數(字典形式)
  • 一個可選的name參數

5.1 Here’s a sample URLconf:

復制代碼
from django.conf.urls import url
from django.contrib import adminfrom app01 import viewsurlpatterns = [url(r'^articles/2003/$', views.special_case_2003),#url(r'^articles/[0-9]{4}/$', views.year_archive),url(r'^articles/([0-9]{4})/$', views.year_archive),  #no_named groupurl(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),]
復制代碼

Note:

 1 #1   There’s no need to add a leading slash, because every URL has that. For
 2 #    example, it’s ^articles, not ^/articles.
 3 
 4 #2   A request to /articles/2005/03/ would match the third entry in the list.
 5 #    Django would call the function views.month_archive(request, '2005', '03').
 6 
 7 #3   /articles/2005/3/ would not match any URL patterns
 8 
 9 #4   /articles/2003/ would match the first pattern in the list, not the second one
10 
11 #5   /articles/2003/03/03/ would match the final pattern. Django would call the
12 #    functionviews.article_detail(request, '2003', '03', '03').
View Code

?

5.2 Named groups

python全棧技能圖。????? The above example used simple,?non-named?regular-expression groups (via parenthesis) to capture bits of the URL and pass them as?positional?arguments to a view. In more advanced usage, it’s possible to use?named?regular-expression groups to capture URL bits and pass them as?keyword?arguments to a view.

?????? In Python regular expressions, the syntax for named regular-expression groups is?(?P<name>pattern), where?name?is the name of the group and?pattern?is some pattern to match.

Here’s the above example URLconf, rewritten to use named groups:

1 import re
2 
3 ret=re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo')
4 
5 print(ret.group())
6 print(ret.group('id'))
7 print(ret.group('name'))
8 
9 ready
ready

==============

復制代碼
from django.conf.urls import urlfrom . import viewsurlpatterns = [url(r'^articles/2003/$', views.special_case_2003),url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
復制代碼

?????? This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments.

5.3? Passing extra options to view functions

pythonweb全棧,?????? URLconfs have a hook that lets you pass extra arguments to your view functions, as a Python dictionary.

The?django.conf.urls.url()?function can take an optional third argument which should be a dictionary of extra keyword arguments to pass to the view function.

For example:

from django.conf.urls import url
from . import viewsurlpatterns = [url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

?????? In this example, for a request to?/blog/2005/, Django will call?views.year_archive(request,?year='2005',foo='bar').

This technique is used in the?syndication framework?to pass metadata and options to views.

Dealing with conflicts

?????? It’s possible to have a URL pattern which captures named keyword arguments, and also passes arguments with the same names in its dictionary of extra arguments. When this happens, the arguments in the dictionary will be used instead of the arguments captured in the URL.

5.4?name param

 1 urlpatterns = [
 2     url(r'^index',views.index,name='bieming'),
 3     url(r'^admin/', admin.site.urls),
 4     # url(r'^articles/2003/$', views.special_case_2003),
 5     url(r'^articles/([0-9]{4})/$', views.year_archive),
 6     # url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
 7     # url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
 8 
 9 ]
10 ###################
11 
12 def index(req):
13     if req.method=='POST':
14         username=req.POST.get('username')
15         password=req.POST.get('password')
16         if username=='alex' and password=='123':
17             return HttpResponse("登陸成功")
18 
19 
20 
21     return render(req,'index.html')
22 
23 #####################
24 
25 <!DOCTYPE html>
26 <html lang="en">
27 <head>
28     <meta charset="UTF-8">
29     <title>Title</title>
30 </head>
31 <body>
32 {#     <form action="/index/" method="post">#}
33      <form action="{% url 'bieming' %}" method="post">
34          用戶名:<input type="text" name="username">
35          密碼:<input type="password" name="password">
36          <input type="submit" value="submit">
37      </form>
38 </body>
39 </html>
40 
41 
42 #######################
View Code

5.5 Including other URLconfs

復制代碼
#At any point, your urlpatterns can “include” other URLconf modules. This
#essentially “roots” a set of URLs below other ones.#For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs:from django.conf.urls import include, urlurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^blog/', include('blog.urls')),
]
復制代碼

六 Django Views(視圖函數)

python的前端框架?

http請求中產生兩個核心對象:

??????? http請求:HttpRequest對象

??????? http響應:HttpResponse對象

所在位置:django.http

python框架django入門。之前我們用到的參數request就是HttpRequest ? ?檢測方法:isinstance(request,HttpRequest)

1 HttpRequest對象的屬性和方法:

 1 # path:       請求頁面的全路徑,不包括域名
 2 #
 3 # method:     請求中使用的HTTP方法的字符串表示。全大寫表示。例如
 4 #
 5 #                    if  req.method=="GET":
 6 #
 7 #                              do_something()
 8 #
 9 #                    elseif req.method=="POST":
10 #
11 #                              do_something_else()
12 #
13 # GET:         包含所有HTTP GET參數的類字典對象
14 #
15 # POST:       包含所有HTTP POST參數的類字典對象
16 #
17 #              服務器收到空的POST請求的情況也是可能發生的,也就是說,表單form通過
18 #              HTTP POST方法提交請求,但是表單中可能沒有數據,因此不能使用
19 #              if req.POST來判斷是否使用了HTTP POST 方法;應該使用  if req.method=="POST"
20 #
21 #
22 #
23 # COOKIES:     包含所有cookies的標準Python字典對象;keys和values都是字符串。
24 #
25 # FILES:      包含所有上傳文件的類字典對象;FILES中的每一個Key都是<input type="file" name="" />標簽中                     name屬性的值,FILES中的每一個value同時也是一個標準的python字典對象,包含下面三個Keys:
26 #
27 #             filename:      上傳文件名,用字符串表示
28 #             content_type:   上傳文件的Content Type
29 #             content:       上傳文件的原始內容
30 #
31 #
32 # user:       是一個django.contrib.auth.models.User對象,代表當前登陸的用戶。如果訪問用戶當前
33 #              沒有登陸,user將被初始化為django.contrib.auth.models.AnonymousUser的實例。你
34 #              可以通過user的is_authenticated()方法來辨別用戶是否登陸:
35 #              if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware
36 #              時該屬性才可用
37 #
38 # session:    唯一可讀寫的屬性,代表當前會話的字典對象;自己有激活Django中的session支持時該屬性才可用。
39 
40 #方法
41 get_full_path(),   比如:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的結果就是/index33/?name=123
42 req.path:/index33
View Code

?

注意一個常用方法:request.POST.getlist('')

2?HttpResponse對象:

? 對于HttpRequest對象來說,是由django自動創建的,但是,HttpResponse對象就必須我們自己創建。每個view請求處理方法必須返回一個HttpResponse對象。

??HttpResponse類在django.http.HttpResponse

? 在HttpResponse對象上擴展的常用方法:

1
2
3
頁面渲染:???????? render()(推薦)<br>???????????????? render_to_response(),
頁面跳轉:???????? redirect("路徑")
locals():??? 可以直接將函數中所有的變量傳給模板

最好的python教程。補充:

 1 -----------------------------------url.py
 2 
 3  url(r"login",   views.login),
 4  url(r"yuan_back",   views.yuan_back),
 5 
 6 -----------------------------------views.py
 7 def login(req):
 8     if req.method=="POST":
 9         if 1:
10             # return redirect("/yuan_back/")
11             name="yuanhao"
12 
13             return render(req,"my backend.html",locals())
14 
15     return render(req,"login.html",locals())
16 
17 
18 def yuan_back(req):
19 
20     name="苑昊"
21 
22     return render(req,"my backend.html",locals())
23 
24 -----------------------------------login.html
25 
26 <form action="/login/" method="post">
27     <p>姓名<input type="text" name="username"></p>
28     <p>性別<input type="text" name="sex"></p>
29     <p>郵箱<input type="text" name="email"></p>
30     <p><input type="submit" value="submit"></p>
31 </form>
32 -----------------------------------my backend.html
33 <h1>用戶{{ name }}你好</h1>
34 
35 #總結: render和redirect的區別:
36 #   1 if render的頁面需要模板語言渲染,需要的將數據庫的數據加載到html,那么所有的這一部分
37 #     除了寫在yuan_back的視圖函數中,必須還要寫在login中,代碼重復,沒有解耦.
38 
39 #   2 the most important: url沒有跳轉到/yuan_back/,而是還在/login/,所以當刷新后
40 #     又得重新登錄.
View Code

?

七 Template基礎?

模板系統的介紹

你可能已經注意到我們在例子視圖中返回文本的方式有點特別。 也就是說,HTML被直接硬編碼在 Python代碼之中。

def current_datetime(request):now = datetime.datetime.now()html = "<html><body>It is now %s.</body></html>" % nowreturn HttpResponse(html)

盡管這種技術便于解釋視圖是如何工作的,但直接將HTML硬編碼到你的視圖里卻并不是一個好主意。 讓我們來看一下為什么:

  • 對頁面設計進行的任何改變都必須對 Python 代碼進行相應的修改。 站點設計的修改往往比底層 Python 代碼的修改要頻繁得多,因此如果可以在不進行 Python 代碼修改的情況下變更設計,那將會方便得多。

  • Python 代碼編寫和 HTML 設計是兩項不同的工作,大多數專業的網站開發環境都將他們分配給不同的人員(甚至不同部門)來完成。 設計者和HTML/CSS的編碼人員不應該被要求去編輯Python的代碼來完成他們的工作。

  • 程序員編寫 Python代碼和設計人員制作模板兩項工作同時進行的效率是最高的,遠勝于讓一個人等待另一個人完成對某個既包含 Python又包含 HTML 的文件的編輯工作。

基于這些原因,將頁面的設計和Python的代碼分離開會更干凈簡潔更容易維護。 我們可以使用 Django的?模板系統?(Template System)來實現這種模式,這就是本章要具體討論的問題。

------------------------------------------------------------------模板語法------------------------------------------------------------------

一模版的組成

組成:HTML代碼+邏輯控制代碼

二 邏輯控制代碼的組成

1 ?變量(使用雙大括號來引用變量):

1
語法格式:?????? {{var_name}}

------Template和Context對象

 1 >>> python manange.py shell  (進入該django項目的環境)
 2 >>> from django.template import Context, Template
 3 >>> t = Template('My name is {{ name }}.')
 4 >>> c = Context({'name': 'Stephane'})
 5 >>> t.render(c)
 6 'My name is Stephane.'
 7 
 8 
 9 # 同一模板,多個上下文,一旦有了模板對象,你就可以通過它渲染多個context,無論何時我們都可以
10 # 像這樣使用同一模板源渲染多個context,只進行 一次模板創建然后多次調用render()方法渲染會
11 # 更為高效:
12 # Low
13 for name in ('John', 'Julie', 'Pat'):
14     t = Template('Hello, {{ name }}')
15     print t.render(Context({'name': name}))
16 
17 # Good
18 t = Template('Hello, {{ name }}')
19 for name in ('John', 'Julie', 'Pat'):
20     print t.render(Context({'name': name}))
View Code

?

?Django 模板解析非常快捷。 大部分的解析工作都是在后臺通過對簡短正則表達式一次性調用來完成。 這和基于 XML 的模板引擎形成鮮明對比,那些引擎承擔了 XML 解析器的開銷,且往往比 Django 模板渲染引擎要慢上幾個數量級。

 1 from django.shortcuts import render,HttpResponse
 2 from django.template.loader import get_template #記得導入
 3 # Create your views here.
 4 
 5 
 6 import datetime
 7 from django.template import Template,Context
 8 
 9 # def current_time(req):
10     #原始的視圖函數
11     # now=datetime.datetime.now()
12     # html="<html><body>現在時刻:<h1>%s.</h1></body></html>" %now
13     # return HttpResponse(html)
14 
15 
16 
17 # def current_time(req):
18 
19       #django模板修改的視圖函數
20 #     now=datetime.datetime.now()
21 #     t=Template('<html><body>現在時刻是:<h1 style="color:red">{{current_date}}</h1></body></html>')
22       #t=get_template('current_datetime.html')
23 #     c=Context({'current_date':now})
24 #     html=t.render(c)
25 #     return HttpResponse(html)
26 
27 #另一種寫法(推薦)
28 
29 def current_time(req):
30 
31     now=datetime.datetime.now()
32 
33     return render(req, 'current_datetime.html', {'current_date':now})
34 
35 推薦方式
推薦方式

?

------深度變量的查找(萬能的句點號)

在到目前為止的例子中,我們通過 context 傳遞的簡單參數值主要是字符串,然而,模板系統能夠非常簡潔地處理更加復雜的數據結構,例如list、dictionary和自定義的對象。

在 Django 模板中遍歷復雜數據結構的關鍵是句點字符 (.)。

 1 #最好是用幾個例子來說明一下。
 2 # 首先,句點可用于訪問列表索引,例如:
 3 
 4 >>> from django.template import Template, Context
 5 >>> t = Template('Item 2 is {{ items.2 }}.')
 6 >>> c = Context({'items': ['apples', 'bananas', 'carrots']})
 7 >>> t.render(c)
 8 'Item 2 is carrots.'
 9 
10 #假設你要向模板傳遞一個 Python 字典。 要通過字典鍵訪問該字典的值,可使用一個句點:
11 >>> from django.template import Template, Context
12 >>> person = {'name': 'Sally', 'age': '43'}
13 >>> t = Template('{{ person.name }} is {{ person.age }} years old.')
14 >>> c = Context({'person': person})
15 >>> t.render(c)
16 'Sally is 43 years old.'
17 
18 #同樣,也可以通過句點來訪問對象的屬性。 比方說, Python 的 datetime.date 對象有
19 #year 、 month 和 day 幾個屬性,你同樣可以在模板中使用句點來訪問這些屬性:
20 
21 >>> from django.template import Template, Context
22 >>> import datetime
23 >>> d = datetime.date(1993, 5, 2)
24 >>> d.year
25 >>> d.month
26 >>> d.day
27 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
28 >>> c = Context({'date': d})
29 >>> t.render(c)
30 'The month is 5 and the year is 1993.'
31 
32 # 這個例子使用了一個自定義的類,演示了通過實例變量加一點(dots)來訪問它的屬性,這個方法適
33 # 用于任意的對象。
34 >>> from django.template import Template, Context
35 >>> class Person(object):
36 ...     def __init__(self, first_name, last_name):
37 ...         self.first_name, self.last_name = first_name, last_name
38 >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
39 >>> c = Context({'person': Person('John', 'Smith')})
40 >>> t.render(c)
41 'Hello, John Smith.'
42 
43 # 點語法也可以用來引用對象的方法。 例如,每個 Python 字符串都有 upper() 和 isdigit()
44 # 方法,你在模板中可以使用同樣的句點語法來調用它們:
45 >>> from django.template import Template, Context
46 >>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
47 >>> t.render(Context({'var': 'hello'}))
48 'hello -- HELLO -- False'
49 >>> t.render(Context({'var': '123'}))
50 '123 -- 123 -- True'
51 
52 # 注意這里調用方法時并* 沒有* 使用圓括號 而且也無法給該方法傳遞參數;你只能調用不需參數的
53 # 方法。
View Code

?

------變量的過濾器(filter)的使用

?1 1 2 語法格式: {{obj|filter:param}}?

 1 # 1  add          :   給變量加上相應的值
 2    #
 3    # 2  addslashes   :    給變量中的引號前加上斜線
 4    #
 5    # 3  capfirst     :    首字母大寫
 6    #
 7    # 4  cut          :   從字符串中移除指定的字符
 8    #
 9    # 5  date         :   格式化日期字符串
10    #
11    # 6  default      :   如果值是False,就替換成設置的默認值,否則就是用本來的值
12    #
13    # 7  default_if_none:  如果值是None,就替換成設置的默認值,否則就使用本來的值
14 
15 
16 #實例:
17 
18 #value1="aBcDe"
19 {{ value1|upper }}<br>
20 
21 #value2=5
22 {{ value2|add:3 }}<br>
23 
24 #value3='he  llo wo r ld'
25 {{ value3|cut:' ' }}<br>
26 
27 #import datetime
28 #value4=datetime.datetime.now()
29 {{ value4|date:'Y-m-d' }}<br>
30 
31 #value5=[]
32 {{ value5|default:'空的' }}<br>
33 
34 #value6='<a href="#">跳轉</a>'
35 
36 {{ value6 }}
37 
38 {% autoescape off %}
39   {{ value6 }}
40 {% endautoescape %}
41 
42 {{ value6|safe }}<br>
43 
44 {{ value6|striptags }}
45 
46 #value7='1234'
47 {{ value7|filesizeformat }}<br>
48 {{ value7|first }}<br>
49 {{ value7|length }}<br>
50 {{ value7|slice:":-1" }}<br>
51 
52 #value8='http://www.baidu.com/?a=1&b=3'
53 {{ value8|urlencode }}<br>
54     value9='hello I am yuan'
View Code

?

2 標簽(tag)的使用(使用大括號和百分比的組合來表示使用tag)

1
{% tags %}

------{% if %} 的使用?

{% if %}標簽計算一個變量值,如果是“true”,即它存在、不為空并且不是false的boolean值,系統則會顯示{% if %}和{% endif %}間的所有內容

 1 {% if num >= 100 and 8 %}
 2 
 3     {% if num > 200 %}
 4         <p>num大于200</p>
 5     {% else %}
 6         <p>num大于100小于200</p>
 7     {% endif %}
 8 
 9 {% elif num < 100%}
10     <p>num小于100</p>
11 
12 {% else %}
13     <p>num等于100</p>
14 
15 {% endif %}
16 
17 
18 
19 {% if %} 標簽接受and,or或者not來測試多個變量值或者否定一個給定的變量
20 {% if %} 標簽不允許同一標簽里同時出現and和or,否則邏輯容易產生歧義,例如下面的標簽是不合法的:
21 
22 {% if obj1 and obj2 or obj3 %}
View Code

?

------{% for %}的使用

{% for %}標簽允許你按順序遍歷一個序列中的各個元素,每次循環模板系統都會渲染{% for %}和{% endfor %}之間的所有內容

 1 <ul>
 2 {% for obj in list %}
 3     <li>{{ obj.name }}</li>
 4 {% endfor %}
 5 </ul>
 6 
 7 
 8 #在標簽里添加reversed來反序循環列表:
 9 
10     {% for obj in list reversed %}
11     ...
12     {% endfor %}
13 
14 #{% for %}標簽可以嵌套:
15 
16     {% for country in countries %}
17         <h1>{{ country.name }}</h1>
18         <ul>
19          {% for city in country.city_list %}
20             <li>{{ city }}</li>
21          {% endfor %}
22         </ul>
23     {% endfor %}
24 
25 
26 #系統不支持中斷循環,系統也不支持continue語句,{% for %}標簽內置了一個forloop模板變量,
27 #這個變量含有一些屬性可以提供給你一些關于循環的信息
28 
29 1,forloop.counter表示循環的次數,它從1開始計數,第一次循環設為1:
30 
31     {% for item in todo_list %}
32         <p>{{ forloop.counter }}: {{ item }}</p>
33     {% endfor %}
34 2,forloop.counter0 類似于forloop.counter,但它是從0開始計數,第一次循環設為0
35 3,forloop.revcounter
36 4,forloop.revcounter0
37 5,forloop.first當第一次循環時值為True,在特別情況下很有用:
38 
39     
40     {% for object in objects %}   
41          {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}   
42          {{ object }}   
43         </li>  
44     {% endfor %}  
45     
46 # 富有魔力的forloop變量只能在循環中得到,當模板解析器到達{% endfor %}時forloop就消失了
47 # 如果你的模板context已經包含一個叫forloop的變量,Django會用{% for %}標簽替代它
48 # Django會在for標簽的塊中覆蓋你定義的forloop變量的值
49 # 在其他非循環的地方,你的forloop變量仍然可用
50 
51 
52 #{% empty %}
53 
54 {{li }}
55       {%  for i in li %}
56           <li>{{ forloop.counter0 }}----{{ i }}</li>
57       {% empty %}
58           <li>this is empty!</li>
59       {% endfor %}
60 
61 #         [11, 22, 33, 44, 55]
62 #            0----11
63 #            1----22
64 #            2----33
65 #            3----44
66 #            4----55
View Code

?

------{%csrf_token%}:csrf_token標簽

? ? ?用于生成csrf_token的標簽,用于防治跨站攻擊驗證。注意如果你在view的index里用的是render_to_response方法,不會生效

???? 其實,這里是會生成一個input標簽,和其他表單標簽一起提交給后臺的。

------{% url %}: ?引用路由配置的地址

1 <form action="{% url "bieming"%}" >
2           <input type="text">
3           <input type="submit"value="提交">
4           {%csrf_token%}
5 </form>
View Code

?

------{% with %}:用更簡單的變量名替代復雜的變量名

?1 {% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}?

------{% verbatim %}: 禁止render

?1 {% verbatim %} 2 {{ hello }} 3 {% endverbatim %}?

------{% load %}:?加載標簽庫?

3?自定義filter和simple_tag

------a、在app中創建templatetags模塊(必須的)

------b、創建任意 .py 文件,如:my_tags.py

 1 from django import template
 2 from django.utils.safestring import mark_safe
 3 
 4 register = template.Library()   #register的名字是固定的,不可改變
 5 
 6 
 7 @register.filter
 8 def filter_multi(v1,v2):
 9     return  v1 * v2
10 
11 
12 @register.simple_tag
13 def simple_tag_multi(v1,v2):
14     return  v1 * v2
15 
16 
17 @register.simple_tag
18 def my_input(id,arg):
19     result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
20     return mark_safe(result)
View Code

?

------c、在使用自定義simple_tag和filter的html文件中導入之前創建的 my_tags.py :{% load my_tags %}

------d、使用simple_tag和filter(如何調用)

 1 -------------------------------.html
 2 {% load xxx %}   #首行
 3     
 4     
 5     
 6     
 7  # num=12
 8 {{ num|filter_multi:2 }} #24
 9 
10 {{ num|filter_multi:"[22,333,4444]" }}
11 
12 
13 {% simple_tag_multi 2 5 %}  參數不限,但不能放在if for語句中
14 {% simple_tag_multi num 5 %}
View Code

?

------e、在settings中的INSTALLED_APPS配置當前app,不然django無法找到自定義的simple_tag.

注意:

filter可以用在if等語句后,simple_tag不可以

1 {% if num|filter_multi:30 > 100 %}
2     {{ num|filter_multi:30 }}
3 {% endif %}
View Code

?

4?extend模板繼承

------include?模板標簽

在講解了模板加載機制之后,我們再介紹一個利用該機制的內建模板標簽:?{%?include?%}?。該標簽允許在(模板中)包含其它的模板的內容。 標簽的參數是所要包含的模板名稱,可以是一個變量,也可以是用單/雙引號硬編碼的字符串。 每當在多個模板中出現相同的代碼時,就應該考慮是否要使用?{%?include?%}?來減少重復。

------extend(繼承)模板標簽

到目前為止,我們的模板范例都只是些零星的 HTML 片段,但在實際應用中,你將用 Django 模板系統來創建整個 HTML 頁面。 這就帶來一個常見的 Web 開發問題: 在整個網站中,如何減少共用頁面區域(比如站點導航)所引起的重復和冗余代碼?

解決該問題的傳統做法是使用?服務器端的 includes?,你可以在 HTML 頁面中使用該指令將一個網頁嵌入到另一個中。 事實上, Django 通過剛才講述的?{%?include?%}?支持了這種方法。 但是用 Django 解決此類問題的首選方法是使用更加優雅的策略——?模板繼承?。

本質上來說,模板繼承就是先構造一個基礎框架模板,而后在其子模板中對它所包含站點公用部分和定義塊進行重載。

讓我們通過修改?current_datetime.html?文件,為?current_datetime?創建一個更加完整的模板來體會一下這種做法:

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
 2 <html lang="en">
 3 <head>
 4     <title>The current time</title>
 5 </head>
 6 <body>
 7     <h1>My helpful timestamp site</h1>
 8     <p>It is now {{ current_date }}.</p>
 9  
10     <hr>
11     <p>Thanks for visiting my site.</p>
12 </body>
13 </html>
View Code

?

這看起來很棒,但如果我們要為?hours_ahead?視圖創建另一個模板會發生什么事情呢?

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
 2 <html lang="en">
 3 <head>
 4     <title>Future time</title>
 5 </head>
 6 <body>
 7     <h1>My helpful timestamp site</h1>
 8     <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
 9  
10     <hr>
11     <p>Thanks for visiting my site.</p>
12 </body>
13 </html>
View Code

?

很明顯,我們剛才重復了大量的 HTML 代碼。 想象一下,如果有一個更典型的網站,它有導航條、樣式表,可能還有一些 JavaScript 代碼,事情必將以向每個模板填充各種冗余的 HTML 而告終。

解決這個問題的服務器端 include 方案是找出兩個模板中的共同部分,將其保存為不同的模板片段,然后在每個模板中進行 include。 也許你會把模板頭部的一些代碼保存為?header.html?文件:

?1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> 2 <html lang="en"> 3 <head>?

你可能會把底部保存到文件?footer.html?:

1 <hr>
2     <p>Thanks for visiting my site.</p>
3 </body>
4 </html>
View Code

?

對基于 include 的策略,頭部和底部的包含很簡單。 麻煩的是中間部分。 在此范例中,每個頁面都有一個<h1>My?helpful?timestamp?site</h1>?標題,但是這個標題不能放在?header.html?中,因為每個頁面的?<title>?是不同的。 如果我們將?<h1>?包含在頭部,我們就不得不包含?<title>?,但這樣又不允許在每個頁面對它進行定制。 何去何從呢?

Django 的模板繼承系統解決了這些問題。 你可以將其視為服務器端 include 的逆向思維版本。 你可以對那些不同?的代碼段進行定義,而不是?共同?代碼段。

第一步是定義?基礎模板,該框架之后將由子模板所繼承。 以下是我們目前所講述范例的基礎模板:

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
 2 <html lang="en">
 3 <head>
 4     <title>{% block title %}{% endblock %}</title>
 5 </head>
 6 <body>
 7     <h1>My helpful timestamp site</h1>
 8     {% block content %}{% endblock %}
 9     {% block footer %}
10     <hr>
11     <p>Thanks for visiting my site.</p>
12     {% endblock %}
13 </body>
14 </html>
View Code

?

這個叫做?base.html?的模板定義了一個簡單的 HTML 框架文檔,我們將在本站點的所有頁面中使用。 子模板的作用就是重載、添加或保留那些塊的內容。 (如果你一直按順序學習到這里,保存這個文件到你的template目錄下,命名為?base.html?.)

我們使用模板標簽:?{%?block?%}?。 所有的?{%?block?%}?標簽告訴模板引擎,子模板可以重載這些部分。 每個{%?block?%}標簽所要做的是告訴模板引擎,該模板下的這一塊內容將有可能被子模板覆蓋。

現在我們已經有了一個基本模板,我們可以修改?current_datetime.html?模板來 使用它:

{% extends "base.html" %}{% block title %}The current time{% endblock %}{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}

?

再為?hours_ahead?視圖創建一個模板,看起來是這樣的:

1 {% extends "base.html" %}
2  
3 {% block title %}Future time{% endblock %}
4  
5 {% block content %}
6 <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
7 {% endblock %}
View Code

?

看起來很漂亮是不是? 每個模板只包含對自己而言?獨一無二?的代碼。 無需多余的部分。 如果想進行站點級的設計修改,僅需修改?base.html?,所有其它模板會立即反映出所作修改。

??????以下是其工作方式:

????? 在加載?current_datetime.html?模板時,模板引擎發現了?{%?extends?%}?標簽, 注意到該模板是一個子模板。 模板引擎立即裝載其父模板,即本例中的?base.html?。此時,模板引擎注意到?base.html?中的三個?{%?block?%}?標簽,并用子模板的內容替換這些 block 。因此,引擎將會使用我們在?{?block?title?%}?中定義的標題,對?{%?block?content?%}?也是如此。 所以,網頁標題一塊將由{%?block?title?%}替換,同樣地,網頁的內容一塊將由?{%?block?content?%}替換。

???? 注意由于子模板并沒有定義?footer?塊,模板系統將使用在父模板中定義的值。 父模板?{%?block?%}?標簽中的內容總是被當作一條退路。繼承并不會影響到模板的上下文。 換句話說,任何處在繼承樹上的模板都可以訪問到你傳到模板中的每一個模板變量。你可以根據需要使用任意多的繼承次數。 使用繼承的一種常見方式是下面的三層法:

   <1> 創建 base.html 模板,在其中定義站點的主要外觀感受。 這些都是不常修改甚至從不修改的部分。<2> 為網站的每個區域創建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。這些模板對base.html 進行拓展,
并包含區域特定的風格與設計。<3> 為每種類型的頁面創建獨立的模板,例如論壇頁面或者圖片庫。 這些模板拓展相應的區域模板。

????? 這個方法可最大限度地重用代碼,并使得向公共區域(如區域級的導航)添加內容成為一件輕松的工作。

以下是使用模板繼承的一些訣竅:

 1 <1>如果在模板中使用 {% extends %} ,必須保證其為模板中的第一個模板標記。 否則,模板繼承將不起作用。
 2 
 3  <2>一般來說,基礎模板中的 {% block %} 標簽越多越好。 記住,子模板不必定義父模板中所有的代碼塊,因此
 4     你可以用合理的缺省值對一些代碼塊進行填充,然后只對子模板所需的代碼塊進行(重)定義。 俗話說,鉤子越
 5     多越好。
 6 
 7  <3>如果發覺自己在多個模板之間拷貝代碼,你應該考慮將該代碼段放置到父模板的某個 {% block %} 中。
 8     如果你需要訪問父模板中的塊的內容,使用 {{ block.super }}這個標簽吧,這一個魔法變量將會表現出父模
 9     板中的內容。 如果只想在上級代碼塊基礎上添加內容,而不是全部重載,該變量就顯得非常有用了。
10 
11  <4>不允許在同一個模板中定義多個同名的 {% block %} 。 存在這樣的限制是因為block 標簽的工作方式是雙向的。
12     也就是說,block 標簽不僅挖了一個要填的坑,也定義了在父模板中這個坑所填充的內容。如果模板中出現了兩個
13     相同名稱的 {% block %} 標簽,父模板將無從得知要使用哪個塊的內容。
View Code

?

八 Models

數據庫的配置

1??? django默認支持sqlite,mysql, oracle,postgresql數據庫。

? ???<1> sqlite

? ? ? ? ? ? django默認使用sqlite的數據庫,默認自帶sqlite的數據庫驅動 , 引擎名稱:django.db.backends.sqlite3

? ? ?<2> mysql

? ? ? ? ? ? 引擎名稱:django.db.backends.mysql

2 ? ?mysql驅動程序

  • ?? MySQLdb(mysql python)
  • ?? mysqlclient
  • ?? MySQL
  • ?? PyMySQL(純python的mysql驅動程序)

3 ? ? 在django的項目中會默認使用sqlite數據庫,在settings里有如下設置:

? ? ? ??? ?

如果我們想要更改數據庫,需要修改如下:

? ? ? ??? ?

DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql', 'NAME': 'books',    #你的數據庫名稱'USER': 'root',   #你的數據庫用戶名'PASSWORD': '', #你的數據庫密碼'HOST': '', #你的數據庫主機,留空默認為localhost'PORT': '3306', #你的數據庫端口
}}

?

注意:

 1 NAME即數據庫的名字,在mysql連接前該數據庫必須已經創建,而上面的sqlite數據庫下的db.sqlite3則是項目自動創建
 2 
 3 USER和PASSWORD分別是數據庫的用戶名和密碼。
 4 
 5 設置完后,再啟動我們的Django項目前,我們需要激活我們的mysql。
 6 
 7 然后,啟動項目,會報錯:no module named MySQLdb
 8 
 9 這是因為django默認你導入的驅動是MySQLdb,可是MySQLdb對于py3有很大問題,所以我們需要的驅動是PyMySQL
10 
11 所以,我們只需要找到項目名文件下的__init__,在里面寫入:
12 
13 import pymysql
14 pymysql.install_as_MySQLdb()
15 
16 問題解決!
View Code

?

ORM(對象關系映射)

用于實現面向對象編程語言里不同類型系統的數據之間的轉換,換言之,就是用面向對象的方式去操作數據庫的創建表以及增刪改查等操作。

優點: 1 ORM使得我們的通用數據庫交互變得簡單易行,而且完全不用考慮該死的SQL語句。快速開發,由此而來。

? ? ? ? ? 2 可以避免一些新手程序猿寫sql語句帶來的性能問題。

? ? ? ? ? ? 比如 我們查詢User表中的所有字段:

? ? ? ? ? ??

? ? ? ? ? ? 新手可能會用select * from ?auth_user,這樣會因為多了一個匹配動作而影響效率的。

?缺點:1? 性能有所犧牲,不過現在的各種ORM框架都在嘗試各種方法,比如緩存,延遲加載登來減輕這個問題。效果很顯著。

? ? ? ? ? 2 ?對于個別復雜查詢,ORM仍然力不從心,為了解決這個問題,ORM一般也支持寫raw sql。

????????? 3? 通過QuerySet的query屬性查詢對應操作的sql語句

?1 author_obj=models.Author.objects.filter(id=2) 2 print(author_obj.query)?

? ? ?下面要開始學習Django ORM語法了,為了更好的理解,我們來做一個基本的 書籍/作者/出版商 數據庫結構。 我們這樣做是因為 這是一個眾所周知的例子,很多SQL有關的書籍也常用這個舉例。

表(模型)的創建:

實例:我們來假定下面這些概念,字段和關系

作者模型:一個作者有姓名。

作者詳細模型:把作者的詳情放到詳情表,包含性別,email地址和出生日期,作者詳情模型和作者模型之間是一對一的關系(one-to-one)(類似于每個人和他的身份證之間的關系),在大多數情況下我們沒有必要將他們拆分成兩張表,這里只是引出一對一的概念。

出版商模型:出版商有名稱,地址,所在城市,省,國家和網站。

書籍模型:書籍有書名和出版日期,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關系就是多對多的關聯關系(many-to-many),一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關系(one-to-many),也被稱作外鍵。

 1 from django.db import models<br>
 2 class Publisher(models.Model):
 3     name = models.CharField(max_length=30, verbose_name="名稱")
 4     address = models.CharField("地址", max_length=50)
 5     city = models.CharField('城市',max_length=60)
 6     state_province = models.CharField(max_length=30)
 7     country = models.CharField(max_length=50)
 8     website = models.URLField()
 9  
10     class Meta:
11         verbose_name = '出版商'
12         verbose_name_plural = verbose_name
13  
14     def __str__(self):
15         return self.name
16  
17 class Author(models.Model):
18     name = models.CharField(max_length=30)
19     def __str__(self):
20         return self.name
21  
22 class AuthorDetail(models.Model):
23     sex = models.BooleanField(max_length=1, choices=((0, ''),(1, ''),))
24     email = models.EmailField()
25     address = models.CharField(max_length=50)
26     birthday = models.DateField()
27     author = models.OneToOneField(Author)
28  
29 class Book(models.Model):
30     title = models.CharField(max_length=100)
31     authors = models.ManyToManyField(Author)
32     publisher = models.ForeignKey(Publisher)
33     publication_date = models.DateField()
34     price=models.DecimalField(max_digits=5,decimal_places=2,default=10)
35     def __str__(self):
36         return self.title
View Code

?

注意1:記得在settings里的INSTALLED_APPS中加入'app01',然后再同步數據庫。

注意2: models.ForeignKey("Publish") & models.ForeignKey(Publish)

分析代碼:

? ? ?? <1>? 每個數據模型都是django.db.models.Model的子類,它的父類Model包含了所有必要的和數據庫交互的方法。并提供了一個簡介漂亮的定義數據庫字段的語法。

? ? ?? <2>? 每個模型相當于單個數據庫表(多對多關系例外,會多生成一張關系表),每個屬性也是這個表中的字段。屬性名就是字段名,它的類型(例如CharField)相當于數據庫的字段類型(例如varchar)。大家可以留意下其它的類型都和數據庫里的什么字段對應。

? ? ?? <3>? 模型之間的三種關系:一對一,一對多,多對多。

? ? ? ? ? ? ?一對一:實質就是在主外鍵(author_id就是foreign key)的關系基礎上,給外鍵加了一個UNIQUE=True的屬性;

? ? ? ? ? ?? 一對多:就是主外鍵關系;(foreign key)

? ? ? ? ? ?? 多對多:(ManyToManyField) 自動創建第三張表(當然我們也可以自己創建第三張表:兩個foreign key)

? ? ?? <4> ?模型常用的字段類型參數

  1 <1> CharField
  2         #字符串字段, 用于較短的字符串.
  3         #CharField 要求必須有一個參數 maxlength, 用于從數據庫層和Django校驗層限制該字段所允許的最大字符數.
  4 
  5 <2> IntegerField
  6        #用于保存一個整數.
  7 
  8 <3> FloatField
  9         # 一個浮點數. 必須 提供兩個參數:
 10         #
 11         # 參數    描述
 12         # max_digits    總位數(不包括小數點和符號)
 13         # decimal_places    小數位數
 14                 # 舉例來說, 要保存最大值為 999 (小數點后保存2位),你要這樣定義字段:
 15                 #
 16                 # models.FloatField(..., max_digits=5, decimal_places=2)
 17                 # 要保存最大值一百萬(小數點后保存10位)的話,你要這樣定義:
 18                 #
 19                 # models.FloatField(..., max_digits=19, decimal_places=10)
 20                 # admin 用一個文本框(<input type="text">)表示該字段保存的數據.
 21 
 22 <4> AutoField
 23         # 一個 IntegerField, 添加記錄時它會自動增長. 你通常不需要直接使用這個字段; 
 24         # 自定義一個主鍵:my_id=models.AutoField(primary_key=True)
 25         # 如果你不指定主鍵的話,系統會自動添加一個主鍵字段到你的 model.
 26 
 27 <5> BooleanField
 28         # A true/false field. admin 用 checkbox 來表示此類字段.
 29 
 30 <6> TextField
 31         # 一個容量很大的文本字段.
 32         # admin 用一個 <textarea> (文本區域)表示該字段數據.(一個多行編輯框).
 33 
 34 <7> EmailField
 35         # 一個帶有檢查Email合法性的 CharField,不接受 maxlength 參數.
 36 
 37 <8> DateField
 38         # 一個日期字段. 共有下列額外的可選參數:
 39         # Argument    描述
 40         # auto_now    當對象被保存時,自動將該字段的值設置為當前時間.通常用于表示 "last-modified" 時間戳.
 41         # auto_now_add    當對象首次被創建時,自動將該字段的值設置為當前時間.通常用于表示對象創建時間.
 42         #(僅僅在admin中有意義...)
 43 
 44 <9> DateTimeField
 45         #  一個日期時間字段. 類似 DateField 支持同樣的附加選項.
 46 
 47 <10> ImageField
 48         # 類似 FileField, 不過要校驗上傳對象是否是一個合法圖片.#它有兩個可選參數:height_field和width_field,
 49         # 如果提供這兩個參數,則圖片將按提供的高度和寬度規格保存.     
 50 <11> FileField
 51      # 一個文件上傳字段.
 52      #要求一個必須有的參數: upload_to, 一個用于保存上載文件的本地文件系統路徑. 這個路徑必須包含 strftime #formatting, 
 53      #該格式將被上載文件的 date/time 
 54      #替換(so that uploaded files don't fill up the given directory).
 55      # admin 用一個<input type="file">部件表示該字段保存的數據(一個文件上傳部件) .
 56 
 57      #注意:在一個 model 中使用 FileField 或 ImageField 需要以下步驟:
 58             #(1)在你的 settings 文件中, 定義一個完整路徑給 MEDIA_ROOT 以便讓 Django在此處保存上傳文件. 
 59             # (出于性能考慮,這些文件并不保存到數據庫.) 定義MEDIA_URL 作為該目錄的公共 URL. 要確保該目錄對 
 60             #  WEB服務器用戶帳號是可寫的.
 61             #(2) 在你的 model 中添加 FileField 或 ImageField, 并確保定義了 upload_to 選項,以告訴 Django
 62             # 使用 MEDIA_ROOT 的哪個子目錄保存上傳文件.你的數據庫中要保存的只是文件的路徑(相對于 MEDIA_ROOT). 
 63             # 出于習慣你一定很想使用 Django 提供的 get_<#fieldname>_url 函數.舉例來說,如果你的 ImageField 
 64             # 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 這樣的方式得到圖像的絕對路徑.
 65 
 66 <12> URLField
 67       # 用于保存 URL. 若 verify_exists 參數為 True (默認), 給定的 URL 會預先檢查是否存在( 即URL是否被有效裝入且
 68       # 沒有返回404響應).
 69       # admin 用一個 <input type="text"> 文本框表示該字段保存的數據(一個單行編輯框)
 70 
 71 <13> NullBooleanField
 72        # 類似 BooleanField, 不過允許 NULL 作為其中一個選項. 推薦使用這個字段而不要用 BooleanField 加 null=True 選項
 73        # admin 用一個選擇框 <select> (三個可選擇的值: "Unknown", "Yes" 和 "No" ) 來表示這種字段數據.
 74 
 75 <14> SlugField
 76        # "Slug" 是一個報紙術語. slug 是某個東西的小小標記(短簽), 只包含字母,數字,下劃線和連字符.#它們通常用于URLs
 77        # 若你使用 Django 開發版本,你可以指定 maxlength. 若 maxlength 未指定, Django 會使用默認長度: 50.  #在
 78        # 以前的 Django 版本,沒有任何辦法改變50 這個長度.
 79        # 這暗示了 db_index=True.
 80        # 它接受一個額外的參數: prepopulate_from, which is a list of fields from which to auto-#populate 
 81        # the slug, via JavaScript,in the object's admin form: models.SlugField
 82        # (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields.
 83 
 84 <13> XMLField
 85         #一個校驗值是否為合法XML的 TextField,必須提供參數: schema_path, 它是一個用來校驗文本的 RelaxNG schema #的文件系統路徑.
 86 
 87 <14> FilePathField
 88         # 可選項目為某個特定目錄下的文件名. 支持三個特殊的參數, 其中第一個是必須提供的.
 89         # 參數    描述
 90         # path    必需參數. 一個目錄的絕對文件系統路徑. FilePathField 據此得到可選項目. 
 91         # Example: "/home/images".
 92         # match    可選參數. 一個正則表達式, 作為一個字符串, FilePathField 將使用它過濾文件名.  
 93         # 注意這個正則表達式只會應用到 base filename 而不是
 94         # 路徑全名. Example: "foo.*\.txt^", 將匹配文件 foo23.txt 卻不匹配 bar.txt 或 foo23.gif.
 95         # recursive可選參數.要么 True 要么 False. 默認值是 False. 是否包括 path 下面的全部子目錄.
 96         # 這三個參數可以同時使用.
 97         # match 僅應用于 base filename, 而不是路徑全名. 那么,這個例子:
 98         # FilePathField(path="/home/images", match="foo.*", recursive=True)
 99         # ...會匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif
100 
101 <15> IPAddressField
102         # 一個字符串形式的 IP 地址, (i.e. "24.124.1.30").
103 <16># CommaSeparatedIntegerField
104         # 用于存放逗號分隔的整數值. 類似 CharField, 必須要有maxlength參數.
View Code

?

?????? <5>??Field重要參數

 1 <1> null : 數據庫中字段是否可以為空
 2 
 3     <2> blank: django的 Admin 中添加數據時是否可允許空值
 4 
 5     <3> default:設定缺省值
 6 
 7     <4> editable:如果為假,admin模式下將不能改寫。缺省為真
 8 
 9     <5> primary_key:設置主鍵,如果沒有設置django創建表時會自動加上:
10         id = meta.AutoField('ID', primary_key=True)
11         primary_key=True implies blank=False, null=False and unique=True. Only one
12         primary key is allowed on an object.
13 
14     <6> unique:數據唯一
15 
16     <7> verbose_name  Admin中字段的顯示名稱
17 
18     <8> validator_list:有效性檢查。非有效產生 django.core.validators.ValidationError 錯誤
19 
20 
21     <9> db_column,db_index 如果為真將為此字段創建索引
22 
23     <10>choices:一個用來選擇值的2維元組。第一個值是實際存儲的值,第二個用來方便進行選擇。
24                 如SEX_CHOICES= (( ‘F’,'Female’),(‘M’,'Male’),)
25                 gender = models.CharField(max_length=2,choices = SEX_CHOICES)
View Code

?

表的操作(增刪改查):

-------------------------------------增(create? ,? save)?-------------------------------

復制代碼
from app01.models import *#create方式一:   Author.objects.create(name='Alvin')#create方式二:   Author.objects.create(**{"name":"alex"})#save方式一:     author=Author(name="alvin")author.save()#save方式二:     author=Author()author.name="alvin"author.save()
復制代碼

重點來了------->那么如何創建存在一對多或多對多關系的一本書的信息呢?(如何處理外鍵關系的字段如一對多的publisher和多對多的authors)

 1 #一對多(ForeignKey):
 2 
 3     #方式一: 由于綁定一對多的字段,比如publish,存到數據庫中的字段名叫publish_id,所以我們可以直接給這個
 4     #       字段設定對應值:
 5            Book.objects.create(title='php',
 6                                publisher_id=2,   #這里的2是指為該book對象綁定了Publisher表中id=2的行對象
 7                                publication_date='2017-7-7',
 8                                price=99)
 9 
10 
11     #方式二:
12     #       <1> 先獲取要綁定的Publisher對象:
13         pub_obj=Publisher(name='河大出版社',address='保定',city='保定',
14                 state_province='河北',country='China',website='http://www.hbu.com')
15     OR  pub_obj=Publisher.objects.get(id=1)
16 
17     #       <2>將 publisher_id=2 改為  publisher=pub_obj
18 
19 #多對多(ManyToManyField()):
20 
21     author1=Author.objects.get(id=1)
22     author2=Author.objects.filter(name='alvin')[0]
23     book=Book.objects.get(id=1)
24     book.authors.add(author1,author2)
25     #等同于:
26     book.authors.add(*[author1,author2])
27     book.authors.remove(*[author1,author2])
28     #-------------------
29     book=models.Book.objects.filter(id__gt=1)
30     authors=models.Author.objects.filter(id=1)[0]
31     authors.book_set.add(*book)
32     authors.book_set.remove(*book)
33     #-------------------
34     book.authors.add(1)
35     book.authors.remove(1)
36     authors.book_set.add(1)
37     authors.book_set.remove(1)
38 
39 #注意: 如果第三張表是通過models.ManyToManyField()自動創建的,那么綁定關系只有上面一種方式
40 #     如果第三張表是自己創建的:
41      class Book2Author(models.Model):
42             author=models.ForeignKey("Author")
43             Book=  models.ForeignKey("Book")
44 #     那么就還有一種方式:
45             author_obj=models.Author.objects.filter(id=2)[0]
46             book_obj  =models.Book.objects.filter(id=3)[0]
47 
48             s=models.Book2Author.objects.create(author_id=1,Book_id=2)
49             s.save()
50             s=models.Book2Author(author=author_obj,Book_id=1)
51             s.save()
View Code

?

-----------------------------------------刪(delete)?---------------------------------------------

>>> Book.objects.filter(id=1).delete()
(3, {'app01.Book_authors': 2, 'app01.Book': 1})

我們表面上刪除了一條信息,實際卻刪除了三條,因為我們刪除的這本書在Book_authors表中有兩條相關信息,這種刪除方式就是django默認的級聯刪除。

如果是多對多的關系: remove()和clear()方法:?

復制代碼
#正向
book = models.Book.objects.filter(id=1)#刪除第三張表中和女孩1關聯的所有關聯信息
book.author.clear()        #清空與book中id=1 關聯的所有數據
book.author.remove(2)  #可以為id
book.author.remove(*[1,2,3,4])     #可以為列表,前面加*#反向
author = models.Author.objects.filter(id=1)
author.book_set.clear() #清空與boy中id=1 關聯的所有數據
復制代碼

-----------------------------------------改(update和save)?----------------------------------------

實例:

? ??

注意:

<1> 第二種方式修改不能用get的原因是:update是QuerySet對象的方法,get返回的是一個model對象,它沒有update方法,而filter返回的是一個QuerySet對象(filter里面的條件可能有多個條件符合,比如name='alvin',可能有兩個name='alvin'的行數據)。

<2>在“插入和更新數據”小節中,我們有提到模型的save()方法,這個方法會更新一行里的所有列。 而某些情況下,我們只需要更新行里的某幾列。

 1 #---------------- update方法直接設定對應屬性----------------
 2     models.Book.objects.filter(id=3).update(title="PHP")
 3     ##sql:
 4     ##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3)
 5 
 6 
 7 #--------------- save方法會將所有屬性重新設定一遍,效率低-----------
 8     obj=models.Book.objects.filter(id=3)[0]
 9     obj.title="Python"
10     obj.save()
11 # SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", 
12 # "app01_book"."color", "app01_book"."page_num", 
13 # "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1; 
14 # 
15 # UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556,
16 # "publisher_id" = 1 WHERE "app01_book"."id" = 3;
View Code

?

????? 在這個例子里我們可以看到Django的save()方法更新了不僅僅是title列的值,還有更新了所有的列。 若title以外的列有可能會被其他的進程所改動的情況下,只更改title列顯然是更加明智的。更改某一指定的列,我們可以調用結果集(QuerySet)對象的update()方法,與之等同的SQL語句變得更高效,并且不會引起競態條件。

此外,update()方法對于任何結果集(QuerySet)均有效,這意味著你可以同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。

注意,這里因為update返回的是一個整形,所以沒法用query屬性;對于每次創建一個對象,想顯示對應的raw sql,需要在settings加上日志記錄部分:

 1 LOGGING = {
 2     'version': 1,
 3     'disable_existing_loggers': False,
 4     'handlers': {
 5         'console':{
 6             'level':'DEBUG',
 7             'class':'logging.StreamHandler',
 8         },
 9     },
10     'loggers': {
11         'django.db.backends': {
12             'handlers': ['console'],
13             'propagate': True,
14             'level':'DEBUG',
15         },
16     }
17 }
18 
19 LOGGING
LOGGING

?

注意:如果是多對多的改:

?

    obj=Book.objects.filter(id=1)[0]author=Author.objects.filter(id__gt=2)obj.author.clear()obj.author.add(*author)

?

?

---------------------------------------查(filter,value等)?-------------------------------------

---------->查詢API:

 1 # 查詢相關API:
 2 
 3 #  <1>filter(**kwargs):      它包含了與所給篩選條件相匹配的對象
 4 
 5 #  <2>all():                 查詢所有結果
 6 
 7 #  <3>get(**kwargs):         返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
 8 
 9 #-----------下面的方法都是對查詢的結果再進行處理:比如 objects.filter.values()--------
10 
11 #  <4>values(*field):        返回一個ValueQuerySet——一個特殊的QuerySet,運行后得到的并不是一系列 model的實例化對象,而是一個可迭代的字典序列
12                                      
13 #  <5>exclude(**kwargs):     它包含了與所給篩選條件不匹配的對象
14 
15 #  <6>order_by(*field):      對查詢結果排序
16 
17 #  <7>reverse():             對查詢結果反向排序
18 
19 #  <8>distinct():            從返回結果中剔除重復紀錄
20 
21 #  <9>values_list(*field):   它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列
22 
23 #  <10>count():              返回數據庫中匹配查詢(QuerySet)的對象數量。
24 
25 # <11>first():               返回第一條記錄
26 
27 # <12>last():                返回最后一條記錄
28 
29 #  <13>exists():             如果QuerySet包含數據,就返回True,否則返回False。
View Code

?

補充:

 1 #擴展查詢,有時候DJANGO的查詢API不能方便的設置查詢條件,提供了另外的擴展查詢方法extra:
 2 #extra(select=None, where=None, params=None, tables=None,order_by=None, select_params=None
 3 
 4 (1)  Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
 5 (2)  Blog.objects.extra(
 6         select=SortedDict([('a', '%s'), ('b', '%s')]),
 7         select_params=('one', 'two'))
 8 
 9 (3)  q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
10      q = q.extra(order_by = ['-is_recent'])
11 
12 (4)  Entry.objects.extra(where=['headline=%s'], params=['Lennon'])  
13 
14 extra
extra

?

---------->惰性機制:

所謂惰性機制:Publisher.objects.all()或者.filter()等都只是返回了一個QuerySet(查詢結果集對象),它并不會馬上執行sql,而是當調用QuerySet的時候才執行。

QuerySet特點:

? ? ?? <1>? 可迭代的

? ? ?? <2>? 可切片

 1 #objs=models.Book.objects.all()#[obj1,obj2,ob3...]
 2 
 3     #QuerySet:   可迭代
 4 
 5     # for obj in objs:#每一obj就是一個行對象
 6     #     print("obj:",obj)
 7     # QuerySet:  可切片
 8 
 9     # print(objs[1])
10     # print(objs[1:4])
11     # print(objs[::-1])
View Code

?

QuerySet的高效使用:

 1 <1>Django的queryset是惰性的
 2 
 3      Django的queryset對應于數據庫的若干記錄(row),通過可選的查詢來過濾。例如,下面的代碼會得
 4      到數據庫中名字為‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
 5      上面的代碼并沒有運行任何的數據庫查詢。你可以使用person_set,給它加上一些過濾條件,或者將它傳給某個函數,
 6      這些操作都不會發送給數據庫。這是對的,因為數據庫查詢是顯著影響web應用性能的因素之一。
 7 
 8 <2>要真正從數據庫獲得數據,你可以遍歷queryset或者使用if queryset,總之你用到數據時就會執行sql.
 9    為了驗證這些,需要在settings里加入 LOGGING(驗證方式)
10         obj=models.Book.objects.filter(id=3)
11         # for i in obj:
12         #     print(i)
13 
14         # if obj:
15         #     print("ok")
16 
17 <3>queryset是具有cache的
18      當你遍歷queryset時,所有匹配的記錄會從數據庫獲取,然后轉換成Django的model。這被稱為執行
19     (evaluation).這些model會保存在queryset內置的cache中,這樣如果你再次遍歷這個queryset,
20      你不需要重復運行通用的查詢。
21         obj=models.Book.objects.filter(id=3)
22 
23         # for i in obj:
24         #     print(i)
25                           ## models.Book.objects.filter(id=3).update(title="GO")
26                           ## obj_new=models.Book.objects.filter(id=3)
27         # for i in obj:
28         #     print(i)   #LOGGING只會打印一次
29 
30 <4>
31      簡單的使用if語句進行判斷也會完全執行整個queryset并且把數據放入cache,雖然你并不需要這些
32      數據!為了避免這個,可以用exists()方法來檢查是否有數據:
33 
34             obj = Book.objects.filter(id=4)
35             #  exists()的檢查可以避免數據放入queryset的cache。
36             if obj.exists():
37                 print("hello world!")
38 
39 <5>當queryset非常巨大時,cache會成為問題
40 
41      處理成千上萬的記錄時,將它們一次裝入內存是很浪費的。更糟糕的是,巨大的queryset可能會鎖住系統
42      進程,讓你的程序瀕臨崩潰。要避免在遍歷數據的同時產生queryset cache,可以使用iterator()方法
43      來獲取數據,處理完數據就將其丟棄。
44         objs = Book.objects.all().iterator()
45         # iterator()可以一次只從數據庫獲取少量數據,這樣可以節省內存
46         for obj in objs:
47             print(obj.name)
48         #BUT,再次遍歷沒有打印,因為迭代器已經在上一次遍歷(next)到最后一次了,沒得遍歷了
49         for obj in objs:
50             print(obj.name)
51 
52      #當然,使用iterator()方法來防止生成cache,意味著遍歷同一個queryset時會重復執行查詢。所以使
53      #用iterator()的時候要當心,確保你的代碼在操作一個大的queryset時沒有重復執行查詢
54 
55 總結:
56     queryset的cache是用于減少程序對數據庫的查詢,在通常的使用下會保證只有在需要的時候才會查詢數據庫。
57 使用exists()和iterator()方法可以優化程序對內存的使用。不過,由于它們并不會生成queryset cache,可能
58 會造成額外的數據庫查詢。
View Code

?

---------->對象查詢,單表條件查詢,多表條件關聯查詢

 1 #--------------------對象形式的查找--------------------------
 2     # 正向查找
 3     ret1=models.Book.objects.first()
 4     print(ret1.title)
 5     print(ret1.price)
 6     print(ret1.publisher)
 7     print(ret1.publisher.name)  #因為一對多的關系所以ret1.publisher是一個對象,而不是一個queryset集合
 8 
 9     # 反向查找
10     ret2=models.Publish.objects.last()
11     print(ret2.name)
12     print(ret2.city)
13     #如何拿到與它綁定的Book對象呢?
14     print(ret2.book_set.all()) #ret2.book_set是一個queryset集合
15 
16 #---------------了不起的雙下劃線(__)之單表條件查詢----------------
17 
18 #    models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大于1 且 小于10的值
19 #
20 #    models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等于11、22、33的數據
21 #    models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
22 #
23 #    models.Tb1.objects.filter(name__contains="ven")
24 #    models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
25 #
26 #    models.Tb1.objects.filter(id__range=[1, 2])   # 范圍bettwen and
27 #
28 #    startswith,istartswith, endswith, iendswith,
29 
30 #----------------了不起的雙下劃線(__)之多表條件關聯查詢---------------
31 
32 # 正向查找(條件)
33 
34 #     ret3=models.Book.objects.filter(title='Python').values('id')
35 #     print(ret3)#[{'id': 1}]
36 
37       #正向查找(條件)之一對多
38 
39       ret4=models.Book.objects.filter(title='Python').values('publisher__city')
40       print(ret4)  #[{'publisher__city': '北京'}]
41 
42       #正向查找(條件)之多對多
43       ret5=models.Book.objects.filter(title='Python').values('author__name')
44       print(ret5)
45       ret6=models.Book.objects.filter(author__name="alex").values('title')
46       print(ret6)
47 
48       #注意
49       #正向查找的publisher__city或者author__name中的publisher,author是book表中綁定的字段
50       #一對多和多對多在這里用法沒區別
51 
52 # 反向查找(條件)
53 
54     #反向查找之一對多:
55     ret8=models.Publisher.objects.filter(book__title='Python').values('name')
56     print(ret8)#[{'name': '人大出版社'}]  注意,book__title中的book就是Publisher的關聯表名
57 
58     ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors')
59     print(ret9)#[{'book__authors': 1}, {'book__authors': 2}]
60 
61     #反向查找之多對多:
62     ret10=models.Author.objects.filter(book__title='Python').values('name')
63     print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}]
64 
65     #注意
66     #正向查找的book__title中的book是表名Book
67     #一對多和多對多在這里用法沒區別
View Code

?

注意:條件查詢即與對象查詢對應,是指在filter,values等方法中的通過__來明確查詢條件。

---------->聚合查詢和分組查詢

<1> aggregate(*args,**kwargs):

?? 通過對QuerySet進行計算,返回一個聚合值的字典。aggregate()中每一個參數都指定一個包含在字典中的返回值。即在查詢集上生成聚合。

 1 from django.db.models import Avg,Min,Sum,Max
 2 
 3 從整個查詢集生成統計值。比如,你想要計算所有在售書的平均價錢。Django的查詢語法提供了一種方式描述所有
 4 圖書的集合。
 5 
 6 >>> Book.objects.all().aggregate(Avg('price'))
 7 {'price__avg': 34.35}
 8 
 9 aggregate()子句的參數描述了我們想要計算的聚合值,在這個例子中,是Book模型中price字段的平均值
10 
11 aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的
12 標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。如果你想要為聚合值指定
13 一個名稱,可以向聚合子句提供它:
14 >>> Book.objects.aggregate(average_price=Avg('price'))
15 {'average_price': 34.35}
16 
17 
18 如果你也想知道所有圖書價格的最大值和最小值,可以這樣查詢:
19 >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
20 {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
View Code

?

<2> annotate(*args,**kwargs):

?? 可以通過計算查詢結果中每一個對象所關聯的對象集合,從而得出總計值(也可以是平均值或總和),即為查詢集的每一項生成聚合。

?????? 查詢alex出的書總價格??? ? ? ? ? ? ? ? ?

? ? ? ?

? ? ? ? 查詢各個作者出的書的總價格,這里就涉及到分組了,分組條件是authors__name

? ? ? ?? ??

? ? ? ?? 查詢各個出版社最便宜的書價是多少

? ? ? ?

---------->F查詢和Q查詢

僅僅靠單一的關鍵字參數查詢已經很難滿足查詢要求。此時Django為我們提供了F和Q查詢:

 1 # F 使用查詢條件的值,專門取對象中某列值的操作
 2 
 3     # from django.db.models import F
 4     # models.Tb1.objects.update(num=F('num')+1)
 5 
 6 
 7 # Q 構建搜索條件
 8     from django.db.models import Q
 9 
10     #1 Q對象(django.db.models.Q)可以對關鍵字參數進行封裝,從而更好地應用多個查詢
11     q1=models.Book.objects.filter(Q(title__startswith='P')).all()
12     print(q1)#[<Book: Python>, <Book: Perl>]
13 
14     # 2、可以組合使用&,|操作符,當一個操作符是用于兩個Q的對象,它產生一個新的Q對象。
15     Q(title__startswith='P') | Q(title__startswith='J')
16 
17     # 3、Q對象可以用~操作符放在前面表示否定,也可允許否定與不否定形式的組合
18     Q(title__startswith='P') | ~Q(pub_date__year=2005)
19 
20     # 4、應用范圍:
21 
22     # Each lookup function that takes keyword-arguments (e.g. filter(),
23     #  exclude(), get()) can also be passed one or more Q objects as
24     # positional (not-named) arguments. If you provide multiple Q object
25     # arguments to a lookup function, the arguments will be “AND”ed
26     # together. For example:
27 
28     Book.objects.get(
29         Q(title__startswith='P'),
30         Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
31     )
32 
33     #sql:
34     # SELECT * from polls WHERE question LIKE 'P%'
35     #     AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
36 
37     # import datetime
38     # e=datetime.date(2005,5,6)  #2005-05-06
39 
40     # 5、Q對象可以與關鍵字參數查詢一起使用,不過一定要把Q對象放在關鍵字參數查詢的前面。
41     # 正確:
42     Book.objects.get(
43         Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
44         title__startswith='P')
45     # 錯誤:
46     Book.objects.get(
47         question__startswith='P',
48         Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
View Code

?

raw sql

django中models的操作,也是調用了ORM框架來實現的,pymysql 或者mysqldb,所以我們也可以使用原生的SQL語句來操作數據庫!

九 admin的配置

admin是django強大功能之一,它能共從數據庫中讀取數據,呈現在頁面中,進行管理。默認情況下,它的功能已經非常強大,如果你不需要復雜的功能,它已經夠用,但是有時候,一些特殊的功能還需要定制,比如搜索功能,下面這一系列文章就逐步深入介紹如何定制適合自己的admin應用。

如果你覺得英文界面不好用,可以在setting.py 文件中修改以下選項

?1 LANGUAGE_CODE = 'en-us' #LANGUAGE_CODE = 'zh-hans'?

一 ?認識ModelAdmin

? ?管理界面的定制類,如需擴展特定的model界面需從該類繼承。

二 注冊medel類到admin的兩種方式:

? ?? <1> ? 使用register的方法

?1 admin.site.register(Book,MyAdmin)?

? ?? <2> ? 使用register的裝飾器

?1 @admin.register(Book)?

三 掌握一些常用的設置技巧

  • ? ? list_display: ??? 指定要顯示的字段
  • ? ? search_fields:? 指定搜索的字段
  • ? ? list_filter:??????? 指定列表過濾器
  • ? ? ordering:?????? 指定排序字段
復制代碼
from django.contrib import admin
from app01.models import *
# Register your models here.# @admin.register(Book)#----->單給某個表加一個定制
class MyAdmin(admin.ModelAdmin):list_display = ("title","price","publisher")search_fields = ("title","publisher")list_filter = ("publisher",)ordering = ("price",)fieldsets =[(None,               {'fields': ['title']}),('price information', {'fields': ['price',"publisher"], 'classes': ['collapse']}),]admin.site.register(Book,MyAdmin)
admin.site.register(Publish)
admin.site.register(Author)
復制代碼

?

參考文獻:http://www.admin10000.com/document/2220.html

轉載于:https://www.cnblogs.com/Lujun1028/p/9961054.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/137281.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息