框架,即framework,特指爲解決一個開放性問題而設計的具備必定約束性的支撐結構,使用框架能夠幫你快速開發特定的系統,簡單地說,就是你用別人搭建好的舞臺來作表演。html
對於全部的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。python
import socket def handle_request(client): buf = client.recv(1024) client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8")) client.send("<h1 style='color:red'>Hello, yuan</h1>".encode("utf8")) def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost',8001)) sock.listen(5) while True: connection, address = sock.accept() handle_request(connection) connection.close() if __name__ == '__main__': main()
最簡單的Web應用就是先把HTML用文件保存好,用一個現成的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。mysql
若是要動態生成HTML,就須要把上述步驟本身來實現。不過,接受HTTP請求、解析HTTP請求、發送HTTP響應都是苦力活,若是咱們本身來寫這些底層代碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規範。程序員
正確的作法是底層代碼由專門的服務器軟件實現,咱們用Python專一於生成HTML文檔。由於咱們不但願接觸到TCP鏈接、HTTP原始請求和響應格式,因此,須要一個統一的接口,讓咱們專心用Python編寫Web業務。web
這個接口就是WSGI:Web Server Gateway Interface。正則表達式
-----------------------------Do a web framework ourselves---------------------------sql
from wsgiref.simple_server import make_server def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [b'<h1>Hello, web!</h1>'] httpd = make_server('', 8080, application) print('Serving HTTP on port 8000...') # 開始監聽HTTP請求: httpd.serve_forever() 複製代碼
整個application()函數自己沒有涉及到任何解析HTTP的部分,也就是說,底層代碼不須要咱們本身編寫, 咱們只負責在更高層次上考慮如何響應請求就能夠了。 application()函數必須由WSGI服務器來調用。有不少符合WSGI規範的服務器,咱們能夠挑選一個來用。 Python內置了一個WSGI服務器,這個模塊叫wsgiref application()函數就是符合WSGI標準的一個HTTP處理函數,它接收兩個參數: //environ:一個包含全部HTTP請求信息的dict對象; //start_response:一個發送HTTP響應的函數。 在application()函數中,調用: start_response('200 OK', [('Content-Type', 'text/html')]) 就發送了HTTP響應的Header,注意Header只能發送一次,也就是隻能調用一次start_response()函數。 start_response()函數接收兩個參數,一個是HTTP響應碼,一個是一組list表示的HTTP Header,每 個Header用一個包含兩個str的tuple表示。 一般狀況下,都應該把Content-Type頭髮送給瀏覽器。其餘不少經常使用的HTTP Header也應該發送。 而後,函數的返回值b'<h1>Hello, web!</h1>'將做爲HTTP響應的Body發送給瀏覽器。 有了WSGI,咱們關心的就是如何從environ這個dict對象拿到HTTP請求信息,而後構造HTML, 經過start_response()發送Header,最後返回Body。
step2shell
print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) f1=open("index1.html","rb") data1=f1.read() f2=open("index2.html","rb") data2=f2.read() if path=="/yuan": return [data1] elif path=="/alex": return [data2] else: return ["<h1>404</h1>".encode('utf8')]
step3數據庫
from wsgiref.simple_server import make_server def f1(): f1=open("index1.html","rb") data1=f1.read() return [data1] def f2(): f2=open("index2.html","rb") data2=f2.read() return [data2] def application(environ, start_response): print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) if path=="/yuan": return f1() elif path=="/alex": return f2() else: return ["<h1>404</h1>".encode("utf8")] httpd = make_server('', 8502, application) print('Serving HTTP on port 8084...') # 開始監聽HTTP請求: httpd.serve_forever()
step4express
from wsgiref.simple_server import make_server def f1(req): print(req) print(req["QUERY_STRING"]) f1=open("index1.html","rb") data1=f1.read() return [data1] def f2(req): f2=open("index2.html","rb") data2=f2.read() return [data2] import time def f3(req): #模版以及數據庫 f3=open("index3.html","rb") data3=f3.read() times=time.strftime("%Y-%m-%d %X", time.localtime()) data3=str(data3,"utf8").replace("!time!",str(times)) return [data3.encode("utf8")] def routers(): urlpatterns = ( ('/yuan',f1), ('/alex',f2), ("/cur_time",f3) ) return urlpatterns def application(environ, start_response): print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) urlpatterns = routers() func = None for item in urlpatterns: if item[0] == path: func = item[1] break if func: return func(environ) else: return ["<h1>404</h1>".encode("utf8")] httpd = make_server('', 8518, application) print('Serving HTTP on port 8084...') # 開始監聽HTTP請求: httpd.serve_forever()
著名的MVC模式:所謂MVC就是把web應用分爲模型(M),控制器(C),視圖(V)三層;他們之間以一種插件似的,鬆耦合的方式鏈接在一塊兒。
模型負責業務對象與數據庫的對象(ORM),視圖負責與用戶的交互(頁面),控制器(C)接受用戶的輸入調用模型和視圖完成用戶的請求。
Django的MTV模式本質上與MVC模式沒有什麼差異,也是各組件之間爲了保持鬆耦合關係,只是定義上有些許不一樣,Django的MTV分別表明:
Model(模型):負責業務對象與數據庫的對象(ORM)
Template(模版):負責如何把頁面展現給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
此外,Django還有一個url分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Template
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
django-admin.py 是Django的一個用於管理任務的命令行工具,manage.py是對django-admin.py的簡單包裝,每個Django Project裏都會有一個mannage.py。
<1> 建立一個django工程 : django-admin.py startproject mysite
當前目錄下會生成mysite的工程,目錄結構以下:
<2>在mysite目錄下建立blog應用: python manage.py startapp blog
<3>啓動django項目:python manage.py runserver 8080
這樣咱們的django就啓動起來了!當咱們訪問:http://127.0.0.1:8080/時就能夠看到:
<4>生成同步數據庫的腳本:python manage.py makemigrations
同步數據庫: python manage.py migrate
注意:在開發過程當中,數據庫同步誤操做以後,不免會遇到後面不能同步成功的狀況,解決這個問題的一個簡單粗暴方法是把migrations目錄下
的腳本(除__init__.py以外)所有刪掉,再把數據庫刪掉以後建立一個新的數據庫,數據庫同步操做再從新作一遍。
<5>當咱們訪問http://127.0.0.1:8080/admin/時,會出現:
因此咱們須要爲進入這個項目的後臺建立超級管理員:python manage.py createsuperuser,設置好用戶名和密碼後即可登陸啦!
<6>清空數據庫:python manage.py flush
<7>查詢某個命令的詳細信息: django-admin.py help startapp
admin 是Django 自帶的一個後臺數據庫管理系統。
<8>啓動交互界面 :python manage.py shell
這個命令和直接運行 python 進入 shell 的區別是:你能夠在這個 shell 裏面調用當前項目的 models.py 中的 API,對於操做數據,還有一些小測試很是方便。
<9> 終端上輸入python manage.py 能夠看到詳細的列表,在忘記子名稱的時候特別有用。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>建立我的信息</h1> <form action="/userInfor/" method="post"> <p>姓名<input type="text" name="username"></p> <p>性別<input type="text" name="sex"></p> <p>郵箱<input type="text" name="email"></p> <p><input type="submit" value="submit"></p> </form> <hr> <h1>信息展現</h1> <table border="1"> <tr> <td>姓名</td> <td>性別</td> <td>郵箱</td> </tr> {% for i in info_list %} <tr> <td>{{ i.username }}</td> <td>{{ i.sex }}</td> <td>{{ i.email }}</td> </tr> {% endfor %} </table> </body> </html> -----------------------url.py--------------------------------------- url(r'^userInfor/', views.userInfor) -----------------------views.py-------------------------------------- info_list=[] def userInfor(req): if req.method=="POST": username=req.POST.get("username",None) sex=req.POST.get("sex",None) email=req.POST.get("email",None) info={"username":username,"sex":sex,"email":email} info_list.append(info) return render(req,"userInfor.html",{"info_list":info_list})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>建立我的信息</h1> <form action="/userInfor/" method="post"> <p>姓名<input type="text" name="username"></p> <p>性別<input type="text" name="sex"></p> <p>郵箱<input type="text" name="email"></p> <p><input type="submit" value="submit"></p> </form> <hr> <h1>信息展現</h1> <table border="1"> <tr> <td>姓名</td> <td>性別</td> <td>郵箱</td> </tr> {% for i in info_list %} <tr> <td>{{ i.username }}</td> <td>{{ i.sex }}</td> <td>{{ i.email }}</td> </tr> {% endfor %} </table> </body> </html> ----------------------------------------------models.py from django.db import models # Create your models here. class UserInfor(models.Model): username=models.CharField(max_length=64) sex=models.CharField(max_length=64) email=models.CharField(max_length=64) ----------------------------------------------views.py from django.shortcuts import render from app01 import models # Create your views here. def userInfor(req): if req.method=="POST": u=req.POST.get("username",None) s=req.POST.get("sex",None) e=req.POST.get("email",None) #---------表中插入數據方式一 # info={"username":u,"sex":e,"email":e} # models.UserInfor.objects.create(**info) #---------表中插入數據方式二 models.UserInfor.objects.create( username=u, sex=s, email=e ) info_list=models.UserInfor.objects.all() return render(req,"userInfor.html",{"info_list":info_list}) return render(req,"userInfor.html")
APPEND_SLASH Default: True When 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.
URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL模式以及要爲該URL模式調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於這個URL調用這段代碼,對於那個URL調用那段代碼。
1
2
3
|
urlpatterns = [
url(正則表達式, views視圖函數,參數,別名),
]
|
參數說明:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ 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 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), ]
Note:
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:
from django.conf.urls import url from . import views urlpatterns = [ 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.
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 views urlpatterns = [ 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.
#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, url urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/', include('blog.urls')), ]
http請求中產生兩個核心對象:
http請求:HttpRequest對象
http響應:HttpResponse對象
所在位置:django.http
以前咱們用到的參數request就是HttpRequest 檢測方法:isinstance(request,HttpRequest)
對於HttpRequest對象來講,是由django自動建立的,可是,HttpResponse對象就必須咱們本身建立。每一個view請求處理方法必須返回一個HttpResponse對象。
HttpResponse類在django.http.HttpResponse
在HttpResponse對象上擴展的經常使用方法:
1
2
3
|
頁面渲染: render()(推薦)<br> render_to_response(),
頁面跳轉: redirect(
"路徑"
)
locals(): 能夠直接將函數中全部的變量傳給模板
|
補充:
你可能已經注意到咱們在例子視圖中返回文本的方式有點特別。 也就是說,HTML被直接硬編碼在 Python代碼之中。
def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
儘管這種技術便於解釋視圖是如何工做的,但直接將HTML硬編碼到你的視圖裏卻並非一個好主意。 讓咱們來看一下爲何:
對頁面設計進行的任何改變都必須對 Python 代碼進行相應的修改。 站點設計的修改每每比底層 Python 代碼的修改要頻繁得多,所以若是能夠在不進行 Python 代碼修改的狀況下變動設計,那將會方便得多。
Python 代碼編寫和 HTML 設計是兩項不一樣的工做,大多數專業的網站開發環境都將他們分配給不一樣的人員(甚至不一樣部門)來完成。 設計者和HTML/CSS的編碼人員不該該被要求去編輯Python的代碼來完成他們的工做。
程序員編寫 Python代碼和設計人員製做模板兩項工做同時進行的效率是最高的,遠勝於讓一我的等待另外一我的完成對某個既包含 Python又包含 HTML 的文件的編輯工做。
基於這些緣由,將頁面的設計和Python的代碼分離開會更乾淨簡潔更容易維護。 咱們可使用 Django的 模板系統 (Template System)來實現這種模式,這就是本章要具體討論的問題。
------------------------------------------------------------------模板語法------------------------------------------------------------------
組成:HTML代碼+邏輯控制代碼
1
|
語法格式: {{var_name}}
|
------Template和Context對象
Django 模板解析很是快捷。 大部分的解析工做都是在後臺經過對簡短正則表達式一次性調用來完成。 這和基於 XML 的模板引擎造成鮮明對比,那些引擎承擔了 XML 解析器的開銷,且每每比 Django 模板渲染引擎要慢上幾個數量級。
------深度變量的查找(萬能的句點號)
在到目前爲止的例子中,咱們經過 context 傳遞的簡單參數值主要是字符串,然而,模板系統可以很是簡潔地處理更加複雜的數據結構,例如list、dictionary和自定義的對象。
在 Django 模板中遍歷複雜數據結構的關鍵是句點字符 (.)。
------變量的過濾器(filter)的使用
1
|
語法格式: {{obj|filter:param}}
|
1
|
{% tags %}
|
------{% if %} 的使用
{% if %}標籤計算一個變量值,若是是「true」,即它存在、不爲空而且不是false的boolean值,系統則會顯示{% if %}和{% endif %}間的全部內容
------{% for %}的使用
{% for %}標籤容許你按順序遍歷一個序列中的各個元素,每次循環模板系統都會渲染{% for %}和{% endfor %}之間的全部內容
------{%csrf_token%}:csrf_token標籤
用於生成csrf_token的標籤,用於防治跨站攻擊驗證。注意若是你在view的index裏用的是render_to_response方法,不會生效
其實,這裏是會生成一個input標籤,和其餘表單標籤一塊兒提交給後臺的。
------{% url %}: 引用路由配置的地址
------{% with %}:用更簡單的變量名替代複雜的變量名
1
|
{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}
|
------{% verbatim %}: 禁止render
1
2
3
|
{% verbatim %}
{{ hello }}
{% endverbatim %}
|
------{% load %}: 加載標籤庫
------a、在app中建立templatetags模塊(必須的)
------b、建立任意 .py 文件,如:my_tags.py
------c、在使用自定義simple_tag和filter的html文件中導入以前建立的 my_tags.py :{% load my_tags %}
------d、使用simple_tag和filter(如何調用)
------e、在settings中的INSTALLED_APPS配置當前app,否則django沒法找到自定義的simple_tag.
注意:
filter能夠用在if等語句後,simple_tag不能夠
------include 模板標籤
在講解了模板加載機制以後,咱們再介紹一個利用該機制的內建模板標籤: {% include %} 。該標籤容許在(模板中)包含其它的模板的內容。 標籤的參數是所要包含的模板名稱,能夠是一個變量,也能夠是用單/雙引號硬編碼的字符串。 每當在多個模板中出現相同的代碼時,就應該考慮是否要使用 {% include %} 來減小重複。
------extend(繼承)模板標籤
到目前爲止,咱們的模板範例都只是些零星的 HTML 片斷,但在實際應用中,你將用 Django 模板系統來建立整個 HTML 頁面。 這就帶來一個常見的 Web 開發問題: 在整個網站中,如何減小共用頁面區域(好比站點導航)所引發的重複和冗餘代碼?
解決該問題的傳統作法是使用 服務器端的 includes ,你能夠在 HTML 頁面中使用該指令將一個網頁嵌入到另外一箇中。 事實上, Django 經過剛纔講述的 {% include %} 支持了這種方法。 可是用 Django 解決此類問題的首選方法是使用更加優雅的策略—— 模板繼承 。
本質上來講,模板繼承就是先構造一個基礎框架模板,然後在其子模板中對它所包含站點公用部分和定義塊進行重載。
讓咱們經過修改 current_datetime.html 文件,爲 current_datetime 建立一個更加完整的模板來體會一下這種作法:
這看起來很棒,但若是咱們要爲 hours_ahead 視圖建立另外一個模板會發生什麼事情呢?
很明顯,咱們剛纔重複了大量的 HTML 代碼。 想象一下,若是有一個更典型的網站,它有導航條、樣式表,可能還有一些 JavaScript 代碼,事情必將以向每一個模板填充各類冗餘的 HTML 而了結。
解決這個問題的服務器端 include 方案是找出兩個模板中的共同部分,將其保存爲不一樣的模板片斷,而後在每一個模板中進行 include。 也許你會把模板頭部的一些代碼保存爲 header.html 文件:
你可能會把底部保存到文件 footer.html :
對基於 include 的策略,頭部和底部的包含很簡單。 麻煩的是中間部分。 在此範例中,每一個頁面都有一個<h1>My helpful timestamp site</h1> 標題,可是這個標題不能放在 header.html 中,由於每一個頁面的 <title> 是不一樣的。 若是咱們將 <h1> 包含在頭部,咱們就不得不包含 <title> ,但這樣又不容許在每一個頁面對它進行定製。 何去何從呢?
Django 的模板繼承系統解決了這些問題。 你能夠將其視爲服務器端 include 的逆向思惟版本。 你能夠對那些不一樣 的代碼段進行定義,而不是 共同 代碼段。
第一步是定義 基礎模板,該框架以後將由子模板所繼承。 如下是咱們目前所講述範例的基礎模板:
這個叫作 base.html 的模板定義了一個簡單的 HTML 框架文檔,咱們將在本站點的全部頁面中使用。 子模板的做用就是重載、添加或保留那些塊的內容。 (若是你一直按順序學習到這裏,保存這個文件到你的template目錄下,命名爲 base.html .)
咱們使用模板標籤: {% block %} 。 全部的 {% block %} 標籤告訴模板引擎,子模板能夠重載這些部分。 每一個{% block %}標籤所要作的是告訴模板引擎,該模板下的這一塊內容將有可能被子模板覆蓋。
如今咱們已經有了一個基本模板,咱們能夠修改 current_datetime.html 模板來 使用它:
再爲 hours_ahead 視圖建立一個模板,看起來是這樣的:
看起來很漂亮是否是? 每一個模板只包含對本身而言 獨一無二 的代碼。 無需多餘的部分。 若是想進行站點級的設計修改,僅需修改 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> sqlite
django默認使用sqlite的數據庫,默認自帶sqlite的數據庫驅動 , 引擎名稱:django.db.backends.sqlite3
<2> mysql
引擎名稱:django.db.backends.mysql
若是咱們想要更改數據庫,須要修改以下:
注意:
用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換,換言之,就是用面向對象的方式去操做數據庫的建立表以及增刪改查等操做。
優勢: 1 ORM使得咱們的通用數據庫交互變得簡單易行,並且徹底不用考慮該死的SQL語句。快速開發,由此而來。
2 能夠避免一些新手程序猿寫sql語句帶來的性能問題。
好比 咱們查詢User表中的全部字段:
新手可能會用select * from auth_user,這樣會由於多了一個匹配動做而影響效率的。
缺點:1 性能有所犧牲,不過如今的各類ORM框架都在嘗試各類方法,好比緩存,延遲加載登來減輕這個問題。效果很顯著。
2 對於個別複雜查詢,ORM仍然力不從心,爲了解決這個問題,ORM通常也支持寫raw sql。
3 經過QuerySet的query屬性查詢對應操做的sql語句
1
2
|
author_obj=models.Author.objects.filter(id=2)
print(author_obj.query)
|
下面要開始學習Django ORM語法了,爲了更好的理解,咱們來作一個基本的 書籍/做者/出版商 數據庫結構。 咱們這樣作是由於 這是一個衆所周知的例子,不少SQL有關的書籍也經常使用這個舉例。
實例:咱們來假定下面這些概念,字段和關係
做者模型:一個做者有姓名。
做者詳細模型:把做者的詳情放到詳情表,包含性別,email地址和出生日期,做者詳情模型和做者模型之間是一對一的關係(one-to-one)(相似於每一個人和他的身份證之間的關係),在大多數狀況下咱們沒有必要將他們拆分紅兩張表,這裏只是引出一對一的概念。
出版商模型:出版商有名稱,地址,所在城市,省,國家和網站。
書籍模型:書籍有書名和出版日期,一本書可能會有多個做者,一個做者也能夠寫多本書,因此做者和書籍的關係就是多對多的關聯關係(many-to-many),一本書只應該由一個出版商出版,因此出版商和書籍是一對多關聯關係(one-to-many),也被稱做外鍵。
注意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> 模型經常使用的字段類型參數
<5> Field重要參數
-------------------------------------增(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)
-----------------------------------------刪(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()方法,這個方法會更新一行裏的全部列。 而某些狀況下,咱們只須要更新行裏的某幾列。
在這個例子裏咱們能夠看到Django的save()方法更新了不只僅是title列的值,還有更新了全部的列。 若title之外的列有可能會被其餘的進程所改動的狀況下,只更改title列顯然是更加明智的。更改某一指定的列,咱們能夠調用結果集(QuerySet)對象的update()方法,與之等同的SQL語句變得更高效,而且不會引發競態條件。
此外,update()方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。
注意,這裏由於update返回的是一個整形,因此無法用query屬性;對於每次建立一個對象,想顯示對應的raw sql,須要在settings加上日誌記錄部分:
注意:若是是多對多的改:
obj=Book.objects.filter(id=1)[0] author=Author.objects.filter(id__gt=2) obj.author.clear() obj.author.add(*author)
---------------------------------------查(filter,value等) -------------------------------------
---------->查詢API:
補充:
---------->惰性機制:
所謂惰性機制:Publisher.objects.all()或者.filter()等都只是返回了一個QuerySet(查詢結果集對象),它並不會立刻執行sql,而是當調用QuerySet的時候才執行。
QuerySet特色:
<1> 可迭代的
<2> 可切片
QuerySet的高效使用:
---------->對象查詢,單表條件查詢,多表條件關聯查詢
注意:條件查詢即與對象查詢對應,是指在filter,values等方法中的經過__來明確查詢條件。
---------->聚合查詢和分組查詢
<1> aggregate(*args,**kwargs):
經過對QuerySet進行計算,返回一個聚合值的字典。aggregate()中每個參數都指定一個包含在字典中的返回值。即在查詢集上生成聚合。
<2> annotate(*args,**kwargs):
能夠經過計算查詢結果中每個對象所關聯的對象集合,從而得出總計值(也能夠是平均值或總和),即爲查詢集的每一項生成聚合。
查詢alex出的書總價格
查詢各個做者出的書的總價格,這裏就涉及到分組了,分組條件是authors__name
查詢各個出版社最便宜的書價是多少
---------->F查詢和Q查詢
僅僅靠單一的關鍵字參數查詢已經很難知足查詢要求。此時Django爲咱們提供了F和Q查詢:
django中models的操做,也是調用了ORM框架來實現的,pymysql 或者mysqldb,因此咱們也可使用原生的SQL語句來操做數據庫!
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)
|
三 掌握一些經常使用的設置技巧
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
轉自:http://www.cnblogs.com/yuanchenqi/articles/6083427.html