Python的WEB框架有Django、Tornado、Flask 等多種,Django相較與其餘WEB框架其優點爲:大而全,框架自己集成了ORM、模型綁定、模板引擎、緩存、Session等諸多功能。javascript
本文將如下方面帶你們全面瞭解Django框架,筆者使用的版本爲1.10.css
-
流程html
- 基本配置
- 路由系統
- 視圖view
- 模板
- Model
- 中間件
- Form
- 認證系統
- CSRF
- 分頁
- Cookie
- Seesion
- 緩存
- 序列化
- 信號
- admin
1、 Django流程介紹
MVC是衆所周知的模式,即:將應用程序分解成三個組成部分:model(模型),view(視圖),和 controller(控制 器)。其中:
M——管理應用程序的狀態(一般存儲到數據庫中),並約束改變狀態的行爲(或者叫作「業務規則」)。
C——接受外部用戶的操做,根據操做訪問模型獲取數據,並調用「視圖」顯示這些數據。控制器是將「模型」和「視圖」隔離,併成爲兩者之間的聯繫紐帶。
V——負責把數據格式化後呈現給用戶。前端
Django也是一個MVC框架。可是在Django中,控制器接受用戶輸入的部分由框架自行處理,因此 Django 裏更關注的是模型(Model)、模板(Template)和視圖(Views),稱爲 MTV模式:
M 表明模型(Model),即數據存取層。 該層處理與數據相關的全部事務: 如何存取、如何驗證有效性、包含哪些行爲以及數據之間的關係等。
T 表明模板(Template),即表現層。 該層處理與表現相關的決定: 如何在頁面或其餘類型文檔中進行顯示。
V 表明視圖(View),即業務邏輯層。 該層包含存取模型及調取恰當模板的相關邏輯。 你能夠把它看做模型與模板之間的橋樑。java
2、 Django 基本配置
1. 建立django程序
- 終端命令:django-admin startproject sitename (在當前目錄下建立一個Django程序)
- IDE建立Django程序時,本質上都是自動執行上述命令
其餘經常使用命令:python
python manage.py runserver ip:port (啓動服務器,默認ip和端口爲http://127.0.0.1:8000/)mysql
python manage.py startapp appname (新建 app)jquery
python manage.py syncdb (同步數據庫命令,Django 1.7及以上版本須要用如下的命令)git
python manage.py makemigrations (顯示並記錄全部數據的改動)ajax
python manage.py migrate (將改動更新到數據庫)
python manage.py createsuperuser (建立超級管理員)
python manage.py dbshell (數據庫命令行)
python manage.py (查看命令列表)
2. 程序目錄
3. 配置文件
a、數據庫
支持SQLite 3(默認)、PostgreSQL 、MySQL、Oracle數據庫的操做
![](http://static.javashuo.com/static/loading.gif)
# 默認是SQLit 3 的配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # MySQL的配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'dbname', #注意這裏的數據庫應該以utf-8編碼 'USER': 'xxx', 'PASSWORD': 'xxx', 'HOST': '', 'PORT': '', } } # 對於python3的使用者們還須要再加一步操做 # 因爲Django內部鏈接MySQL時使用的是MySQLdb模塊,而python3中還無此模塊,因此須要使用pymysql來代替 # 以下設置放置的與project同名的配置的 __init__.py文件中 import pymysql pymysql.install_as_MySQLdb() # PostgreSQL配置 DATABASES = { 'default': { 'NAME': 'app_data', 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'USER': 'XXX', 'PASSWORD': 'XXX' } # Oracle配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.oracle', 'NAME': 'xe', 'USER': 'a_user', 'PASSWORD': 'a_password', 'HOST': '', 'PORT': '', } } 具體配置
Django框架對於開發者而言高度透明化,對於不一樣數據庫的具體使用方法是一致的,改變數據庫類型只須要變更上述配置便可。
想要了解更多請戳這裏
b、靜態文件添加
![](http://static.javashuo.com/static/loading.gif)
# 首先在項目根目錄下建立static目錄 # 接着在settings.py 文件下添加 STATIC_URL = '/static/' # 默認已添加,使用靜態文件時的前綴 STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), #行末的逗號不能漏 ) # 這樣在template中就能夠導入static目錄下的靜態文件啦 # 例: <script src="/static/jquery-1.12.4.js"></script> settings配置
3、 Django 路由系統
URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL模式以及要爲該URL模式調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於這個URL調用這段代碼,對於那個URL調用那段代碼。URL的加載是從配置文件中開始。
參數說明:
- 一個正則表達式字符串
- 一個可調用對象,一般爲一個視圖函數或一個指定視圖函數路徑的字符串
- 可選的要傳遞給視圖函數的默認參數(字典形式)
- 一個可選的name參數
1. 示例
from django.conf.urls import url from . 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})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
說明:
- 要捕獲從URL中的值,用括號括起來,會當參數傳入 views 視圖。
- 沒有必要添加一個斜線,由於每一個URL都有。例如,它
^articles
不是^/articles
。 - 在
'r'
前面的每一個正則表達式字符串中是可選的,但建議。它告訴Python字符串是「原始」 -沒有什麼字符串中應該進行轉義。
請求示例:
- 一個請求
/articles/2005/03/
會匹配上面列表中的第三條. Django 會調用函數views.month_archive(request, '2005', '03')
. /articles/2005/3/
不會匹配上面列表中的任何條目, 由於第三條的月份須要二位數字./articles/2003/
會匹配上第一條而不是第二條,由於匹配是按照從上到下順序而進行的, Django 會調用函數views.special_case_2003(request)
/articles/2003
不會匹配上面列表中的任何條目, 由於每一個URL應該以 / 結尾./articles/2003/03/03/
會匹配上最後一條. Django 會調用函數views.article_detail(request, '2003', '03', '03')
.
2. 命名組(Named groups)
在上面的簡單例子中,並無使用正則表達式分組,在更高級的用法中,頗有可能使用正則分組來匹配URL而且將分組值經過參數傳遞給view函數。
在Python的正則表達式中,分組的語法是 (?P<name>pattern)
, name表示分組名,pattern表示一些匹配正則.
這裏是一個簡單的小例子:
# 正則知識 import re ret=re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo') print(ret.group()) print(ret.group('id')) print(ret.group('name')) ------------------------------------- 123/ooo 123 ooo
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), ]
For example:
- A request to
/articles/2005/03/
會調用函數views.month_archive(request, year='2005',month='03')
, 而不是views.month_archive(request, '2005', '03')
. - A request to
/articles/2003/03/03/
會調用函數views.article_detail(request, year='2003',month='03', day='03')
.
常見寫法實例:
3. 二級路由(Including)
那若是映射 url 太多怎麼辦,全寫一個在 urlpatterns 顯得繁瑣,so 二級路由應用而生
from django.conf.urls import include, url from apps.main import views as main_views from credit import views as credit_views extra_patterns = [ url(r'^reports/$', credit_views.report), url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report), url(r'^charge/$', credit_views.charge), ] urlpatterns = [ url(r'^$', main_views.homepage), url(r'^help/', include('apps.help.urls')), url(r'^credit/', include(extra_patterns)), ]
在上面這個例子中,若是請求url爲 /credit/reports/
則會調用函數 credit_views.report()
.
使用二級路由也能夠減小代碼冗餘,使代碼更加簡潔易懂
# 原始版本 from django.conf.urls import url from . import views urlpatterns = [ url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/history/$', views.history), url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/edit/$', views.edit), url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/discuss/$', views.discuss), url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/permissions/$', views.permissions), ] # 改進版本 from django.conf.urls import include, url from . import views urlpatterns = [ url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([ url(r'^history/$', views.history), url(r'^edit/$', views.edit), url(r'^discuss/$', views.discuss), url(r'^permissions/$', views.permissions), ])), ]
4. 添加額外的參數
URLconfs 有一個鉤子可讓你加入一些額外的參數到view函數中.
from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}), ]
在上面的例子中,若是一個請求爲 /blog/2005/
, Django 將會調用函數l views.year_archive(request, year='2005',foo='bar')
.
須要注意的是,當你加上參數時,對應函數views.year_archive必須加上一個參數,參數名也必須命名爲 foo,以下:
def year_archive(request, foo): print(foo) return render(request, 'index.html')
5. 別名的使用
url(r'^index',views.index,name='bieming')
url中還支持name參數的配置,若是配置了name屬性,在模板的文件中就可使用name值來代替相應的url值.
咱們來看一個例子:
![](http://static.javashuo.com/static/loading.gif)
urlpatterns = [ url(r'^index',views.index,name='bieming'), url(r'^admin/', admin.site.urls), # url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), # 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), ] ################### def index(req): if req.method=='POST': username=req.POST.get('username') password=req.POST.get('password') if username=='alex' and password=='123': return HttpResponse("登錄成功") return render(req,'index.html') ##################### <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {# <form action="/index/" method="post">#} {# 這裏只要使用bieming便可代替/index #} <form action="{% url 'bieming' %}" method="post"> 用戶名:<input type="text" name="username"> 密碼:<input type="password" name="password"> <input type="submit" value="submit"> </form> </body> </html> ####################### name的應用
6. 指定view的默認配置
# URLconf from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/$', views.page), url(r'^blog/page(?P<num>[0-9]+)/$', views.page), ] # View (in blog/views.py) def page(request, num="1"): # Output the appropriate page of blog entries, according to num. ...
在上述的例子中,兩個 URL 模式指向同一個視圖 views.page
但第一圖案不捕獲從 URL 任何東西。若是第一個模式匹配,該 page()
函數將使用它的默認參數 num
,"1"
。若是第二圖案相匹配時, page()
將使用任何 num
值由正則表達式捕獲。
4、 Django Views(視圖函數)
http請求中產生兩個核心對象:
http請求:HttpRequest對象
http響應:HttpResponse對象
1. HttpRequest對象
當請求一個頁面時,Django 建立一個 HttpRequest
對象包含原數據的請求。而後 Django 加載適當的視圖,經過 HttpRequest
做爲視圖函數的第一個參數。每一個視圖負責返回一個HttpResponse
目標。
![](http://static.javashuo.com/static/loading.gif)
path: 請求頁面的全路徑,不包括域名 method: 請求中使用的HTTP方法的字符串表示。全大寫表示。例如 if req.method=="GET": do_something() elseif req.method=="POST": do_something_else() GET: 包含全部HTTP GET參數的類字典對象 POST: 包含全部HTTP POST參數的類字典對象 服務器收到空的POST請求的狀況也是可能發生的,也就是說,表單form經過 HTTP POST方法提交請求,可是表單中可能沒有數據,所以不能使用 if req.POST來判斷是否使用了HTTP POST 方法;應該使用 if req.method=="POST" COOKIES: 包含全部cookies的標準Python字典對象;keys和values都是字符串。 FILES: 包含全部上傳文件的類字典對象;FILES中的每個Key都是<input type="file" name="" />標籤中 name屬性的值,FILES中的每個value同時也是一個標準的python字典對象,包含下面三個Keys: filename: 上傳文件名,用字符串表示 content_type: 上傳文件的Content Type content: 上傳文件的原始內容 user: 是一個django.contrib.auth.models.User對象,表明當前登錄的用戶。若是訪問用戶當前 沒有登錄,user將被初始化爲django.contrib.auth.models.AnonymousUser的實例。你 能夠經過user的is_authenticated()方法來辨別用戶是否登錄: if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware 時該屬性纔可用 session: 惟一可讀寫的屬性,表明當前會話的字典對象;本身有激活Django中的session支持時該屬性纔可用。 META: 一個標準的Python字典包含全部可用的HTTP頭。可用標題取決於客戶端和服務器,但這裏是一些例子: CONTENT_LENGTH – 請求體的長度(一個字符串)。 CONTENT_TYPE – 請求體的類型。 HTTP_ACCEPT - 爲響應–能夠接受的內容類型。 HTTP_ACCEPT_ENCODING – 接受編碼的響應 HTTP_ACCEPT_LANGUAGE – 接受語言的反應 HTTP_HOST – 客戶端發送的HTTP主機頭。 HTTP_REFERER – 參考頁面 HTTP_USER_AGENT – 客戶端的用戶代理字符串。 QUERY_STRING – 查詢字符串,做爲一個單一的(分析的)字符串。 REMOTE_ADDR – 客戶端的IP地址 REMOTE_HOST – 客戶端的主機名 REMOTE_USER – 用戶經過Web服務器的身份驗證。 REQUEST_METHOD – 字符串,如"GET"或"POST" SERVER_NAME – 服務器的主機名 SERVER_PORT – 服務器的端口(一個字符串)。 HttpRequest對象屬性
2. HttpResponse對象
對於HttpRequest對象來講,是由django自動建立的,可是,HttpResponse對象就必須咱們本身建立。每一個view請求處理方法必須返回一個HttpResponse對象。
在HttpResponse對象上擴展的經常使用方法:
- 頁面渲染:render(推薦),render_to_response,
- 頁面跳轉:redirect
- locals: 能夠直接將對應視圖函數中全部的變量傳給模板
值得注意的是對於頁面渲染的方法中,render和render_to_response使用方法和功能相似,可是render功能更爲強大,推薦使用
3. render()
-
render(
request,
template_name,
context=None,
content_type=None,
status=None,
using=None)
[source]
- 結合給定的模板與一個給定的上下文,返回一個字典HttpResponse在渲染文本對象
所需的參數
template_name 一個模板的使用或模板序列名稱全稱。若是序列是給定的,存在於第一個模板將被使用。
可選參數
context 一組字典的值添加到模板中。默認狀況下,這是一個空的字典。
content_type MIME類型用於生成文檔。
status 爲響應狀態代碼。默認值爲200
using 這個名字一個模板引擎的使用將模板。
from django.shortcuts import render def my_view(request): # View code here... return render(request, 'myapp/index.html', { 'foo': 'bar', }, content_type='application/xhtml+xml') render示例
5、 模板
1. 模板的執行
模版的建立過程,對於模版,其實就是讀取模版(其中嵌套着模版標籤),而後將 Model 中獲取的數據插入到模版中,最後將信息返回給用戶。
# view.py def index(request): return render(request, 'index.html', {'title':'welcome'}) # index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <h1>{{ title }}</h1> </div> </body> </html> 示例
2. 模板語言
模板中也有本身的語言,該語言能夠實現數據展現
- {{ item }}
- {% for item in item_list %} <a>{{ item }}</a> {% endfor %}
forloop.counter
forloop.first
forloop.last - {% if ordered_warranty %} {% else %} {% endif %}
- 母板:{% block title %}{% endblock %}
子板:{% extends "base.html" %}
{% block title %}{% endblock %} - 幫助方法:
{{ item.event_start|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }}
{{ my_list|first|upper }}
{{ name|lower }}
小知識點:在模板語言中字典數據類型的取值是經過dict.xxx而不是dict[xxx]
3. 自定義標籤
由於在模板語言中不可以作運算等一些稍顯複雜的操做,因此在Django中提供了兩種自定製標籤,一種是simple_tag,一種是filter。
simple_tag: 任意傳遞參數,可是不能用做布爾判斷
filter: 最多隻能傳遞二個參數,能夠用做布爾判斷
在這裏着重介紹simple_tag類型,filter的實現相似
a、在app中建立templatetags模塊
b、建立任意 .py 文件,如:xx.py
#!/usr/bin/env python #coding:utf-8 from django import template from django.utils.safestring import mark_safe from django.template.base import resolve_variable, Node, TemplateSyntaxError register = template.Library() @register.simple_tag def my_simple_time(v1,v2,v3): return v1 + v2 + v3 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result) 示例
c、在使用自定義simple_tag的html文件中導入以前建立的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{% my_simple_time 1 2 3%} {% my_input 'id_username' 'hide'%}
e、在settings中配置當前app,否則django沒法找到自定義的simple_tag
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', ) 示例
更多見文檔:https://docs.djangoproject.com/en/1.10/ref/templates/language/
6、 Model
Django提供了一個抽象層(「Model」)來構建和管理Web應用程序的數據。
django中遵循 Code Frist 的原則,即:根據代碼中定義的類來自動生成數據庫表。
關係對象映射(Object Relational Mapping,簡稱ORM)。
1. 建立表
a、基本結構
from django.db import models class userinfo(models.Model): name = models.CharField(max_length=30) email = models.EmailField() memo = models.TextField()
![](http://static.javashuo.com/static/loading.gif)
一、null=True 數據庫中字段是否能夠爲空 二、blank=True django的 Admin 中添加數據時是否可容許空值 三、primary_key = False 主鍵,對AutoField設置主鍵後,就會代替原來的自增 id 列 4、auto_now 和 auto_now_add auto_now 自動建立---不管添加或修改,都是當前操做的時間 auto_now_add 自動建立---永遠是建立時的時間 5、choices GENDER_CHOICE = ( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 6、max_length 7、default 默認值 8、verbose_name Admin中字段的顯示名稱 九、name|db_column 數據庫中的字段名稱 十、unique=True 不容許重複 十一、db_index = True 數據庫索引 十二、editable=True 在Admin裏是否可編輯 1三、error_messages=None 錯誤提示 1四、auto_created=False 自動建立 15、help_text 在Admin中提示幫助信息 1六、validators=[] 1七、upload-to 更多參數
![](http://static.javashuo.com/static/loading.gif)
一、models.AutoField 自增列 = int(11) 若是沒有的話,默認會生成一個名稱爲 id 的列,若是要顯示的自定義一個自增列,必須將給列設置爲主鍵 primary_key=True。 2、models.CharField 字符串字段 必須 max_length 參數 三、models.BooleanField 布爾類型=tinyint(1) 不能爲空,Blank=True 四、models.ComaSeparatedIntegerField 用逗號分割的數字=varchar 繼承CharField,因此必須 max_lenght 參數 5、models.DateField 日期類型 date 對於參數,auto_now = True 則每次更新都會更新這個時間;auto_now_add 則只是第一次建立添加,以後的更新再也不改變。 6、models.DateTimeField 日期類型 datetime 同DateField的參數 七、models.Decimal 十進制小數類型 = decimal 必須指定整數位max_digits和小數位decimal_places 八、models.EmailField 字符串類型(正則表達式郵箱) =varchar 對字符串進行正則表達式 九、models.FloatField 浮點類型 = double 10、models.IntegerField 整形 11、models.BigIntegerField 長整形 integer_field_ranges = { 'SmallIntegerField': (-32768, 32767), 'IntegerField': (-2147483648, 2147483647), 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 'PositiveSmallIntegerField': (0, 32767), 'PositiveIntegerField': (0, 2147483647), } 12、models.IPAddressField 字符串類型(ip4正則表達式) 13、models.GenericIPAddressField 字符串類型(ip4和ip6是可選的) 參數protocol能夠是:both、ipv四、ipv6 驗證時,會根據設置報錯 14、models.NullBooleanField 容許爲空的布爾類型 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 減號、下劃線、字母、數字 18、models.SmallIntegerField 數字 數據庫中的字段有:tinyint、smallint、int、bigint 1九、models.TextField 字符串=longtext 20、models.TimeField 時間 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字符串,地址正則表達式 22、models.BinaryField 二進制 23、models.ImageField 圖片 24、models.FilePathField 文件 更多字段
![](http://static.javashuo.com/static/loading.gif)
class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名 db_table = "table_name" # 聯合索引 index_together = [ ("pub_date", "deadline"), ] # 聯合惟一索引 unique_together = (("driver", "restaurant"),) # admin中顯示的表名稱 verbose_name # verbose_name加s verbose_name_plural 更多:https://docs.djangoproject.com/en/1.10/ref/models/options/ 元信息
![](http://static.javashuo.com/static/loading.gif)
1.觸發Model中的驗證和錯誤提示有兩種方式: a. Django Admin中的錯誤信息會優先根據Admiin內部的ModelForm錯誤信息提示,若是都成功,纔來檢查Model的字段並顯示指定錯誤信息 b. 調用Model對象的 clean_fields 方法,如: # models.py class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) email = models.EmailField(error_messages={'invalid': '格式錯了.'}) # views.py def index(request): obj = models.UserInfo(username='11234', email='uu') try: print(obj.clean_fields()) except Exception as e: print(e) return HttpResponse('ok') # Model的clean方法是一個鉤子,可用於定製操做,如:上述的異常處理。 2.Admin中修改錯誤提示 # admin.py from django.contrib import admin from model_club import models from django import forms class UserInfoForm(forms.ModelForm): username = forms.CharField(error_messages={'required': '用戶名不能爲空.'}) email = forms.EmailField(error_messages={'invalid': '郵箱格式錯誤.'}) age = forms.IntegerField(initial=1, error_messages={'required': '請輸入數值.', 'invalid': '年齡必須爲數值.'}) class Meta: model = models.UserInfo # fields = ('username',) fields = "__all__" class UserInfoAdmin(admin.ModelAdmin): form = UserInfoForm admin.site.register(models.UserInfo, UserInfoAdmin) 拓展知識
b、連表結構
- 一對多:models.ForeignKey(其餘表)
- 多對多:models.ManyToManyField(其餘表)
- 一對一:models.OneToOneField(其餘表)
應用場景:
- 一對多:當一張表中建立一行數據時,有一個單選的下拉框(能夠被重複選擇)
例如:建立用戶信息時候,須要選擇一個用戶類型【普通用戶】【金牌用戶】【鉑金用戶】等。- 多對多:在某表中建立一行數據是,有一個能夠多選的下拉框
例如:建立用戶信息,須要爲用戶指定多個愛好- 一對一:在某表中建立一行數據時,有一個單選的下拉框(下拉框中的內容被用過一次就消失了
例如:原有含10列數據的一張表保存相關信息,通過一段時間以後,10列沒法知足需求,須要爲原來的表再添加5列數據
![](http://static.javashuo.com/static/loading.gif)
ForeignKey(ForeignObject) # ForeignObject(RelatedField) to, # 要進行關聯的表名 to_field=None, # 要關聯的表中的字段名稱 on_delete=None, # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲 - models.CASCADE,刪除關聯數據,與之關聯也刪除 - models.DO_NOTHING,刪除關聯數據,引起錯誤IntegrityError - models.PROTECT,刪除關聯數據,引起錯誤ProtectedError - models.SET_NULL,刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空) - models.SET_DEFAULT,刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值) - models.SET,刪除關聯數據, a. 與之關聯的值設置爲指定值,設置:models.SET(值) b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象) def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id" on_delete=models.SET(func),) related_name=None, # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操做時,使用的鏈接前綴,用於替換【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中顯示關聯數據時,提供的條件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') db_constraint=True # 是否在數據庫中建立外鍵約束 parent_link=False # 在Admin中是否顯示關聯數據 OneToOneField(ForeignKey) to, # 要進行關聯的表名 to_field=None # 要關聯的表中的字段名稱 on_delete=None, # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲 ###### 對於一對一 ###### # 1. 一對一其實就是 一對多 + 惟一索引 # 2.當兩個類之間有繼承關係時,默認會建立一個一對一字段 # 以下會在A表中額外增長一個c_ptr_id列且惟一: class C(models.Model): nid = models.AutoField(primary_key=True) part = models.CharField(max_length=12) class A(C): id = models.AutoField(primary_key=True) code = models.CharField(max_length=1) ManyToManyField(RelatedField) to, # 要進行關聯的表名 related_name=None, # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操做時,使用的鏈接前綴,用於替換【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中顯示關聯數據時,提供的條件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') symmetrical=None, # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段 # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段 models.BB.objects.filter(...) # 可選字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可選字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定義第三張表時,使用字段用於指定關係表 through_fields=None, # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表 from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64) db_constraint=True, # 是否在數據庫中建立外鍵約束 db_table=None, # 默認建立第三張表時,數據庫中表的名稱 字段以及參數
2. 操做表
a、基本操做
![](http://static.javashuo.com/static/loading.gif)
# 增 # # models.Tb1.objects.create(c1='xx', c2='oo') 增長一條數據,能夠接受字典類型數據 **kwargs # obj = models.Tb1(c1='xx', c2='oo') # obj.save() # 查 # # models.Tb1.objects.get(id=123) # 獲取單條數據,不存在則報錯(不建議) # models.Tb1.objects.all() # 獲取所有 # models.Tb1.objects.filter(name='seven') # 獲取指定條件的數據 # 刪 # # models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數據 # 改 # models.Tb1.objects.filter(name='seven').update(gender='0') # 將指定條件的數據更新,均支持 **kwargs # obj = models.Tb1.objects.get(id=1) # obj.c1 = '111' # obj.save() # 修改單條數據 基本操做
b、進階操做(了不得的雙下劃線)
利用雙下劃線將字段和對應的操做鏈接起來
![](http://static.javashuo.com/static/loading.gif)
# 獲取個數 # # models.Tb1.objects.filter(name='seven').count() # 大於,小於 # # models.Tb1.objects.filter(id__gt=1) # 獲取id大於1的值 # models.Tb1.objects.filter(id__gte=1) # 獲取id大於等於1的值 # models.Tb1.objects.filter(id__lt=10) # 獲取id小於10的值 # models.Tb1.objects.filter(id__lte=10) # 獲取id小於10的值 # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 # in # # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於十一、2二、33的數據 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # isnull # Entry.objects.filter(pub_date__isnull=True) # contains # # models.Tb1.objects.filter(name__contains="ven") # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 # models.Tb1.objects.exclude(name__icontains="ven") # range # # models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and # 其餘相似 # # startswith,istartswith, endswith, iendswith, # order by # # models.Tb1.objects.filter(name='seven').order_by('id') # asc # models.Tb1.objects.filter(name='seven').order_by('-id') # desc # group by # # from django.db.models import Count, Min, Max, Sum # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id" # limit 、offset # # models.Tb1.objects.all()[10:20] # regex正則匹配,iregex 不區分大小寫 # # Entry.objects.get(title__regex=r'^(An?|The) +') # Entry.objects.get(title__iregex=r'^(an?|the) +') # date # # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1)) # year # # Entry.objects.filter(pub_date__year=2005) # Entry.objects.filter(pub_date__year__gte=2005) # month # # Entry.objects.filter(pub_date__month=12) # Entry.objects.filter(pub_date__month__gte=6) # day # # Entry.objects.filter(pub_date__day=3) # Entry.objects.filter(pub_date__day__gte=3) # week_day # # Entry.objects.filter(pub_date__week_day=2) # Entry.objects.filter(pub_date__week_day__gte=2) # hour # # Event.objects.filter(timestamp__hour=23) # Event.objects.filter(time__hour=5) # Event.objects.filter(timestamp__hour__gte=12) # minute # # Event.objects.filter(timestamp__minute=29) # Event.objects.filter(time__minute=46) # Event.objects.filter(timestamp__minute__gte=29) # second # # Event.objects.filter(timestamp__second=31) # Event.objects.filter(time__second=2) # Event.objects.filter(timestamp__second__gte=31) 進階操做
c、其餘操做
![](http://static.javashuo.com/static/loading.gif)
# extra # # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) # Entry.objects.extra(where=['headline=%s'], params=['Lennon']) # Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) # Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) # F # # from django.db.models import F # models.Tb1.objects.update(num=F('num')+1) # Q # # 方式一: # Q(nid__gt=10) # Q(nid=8) | Q(nid__gt=10) # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') # 方式二: # con = Q() # q1 = Q() # q1.connector = 'OR' # q1.children.append(('id', 1)) # q1.children.append(('id', 10)) # q1.children.append(('id', 9)) # q2 = Q() # q2.connector = 'OR' # q2.children.append(('c1', 1)) # q2.children.append(('c1', 10)) # q2.children.append(('c1', 9)) # con.add(q1, 'AND') # con.add(q2, 'AND') # # models.Tb1.objects.filter(con) # 執行原生SQL # # from django.db import connection, connections # cursor = connection.cursor() # cursor = connections['default'].cursor() # cursor.execute("""SELECT * from auth_user where id = %s""", [1]) # row = cursor.fetchone() 其餘操做
d、連表操做(了不得的雙下劃線)
利用雙下劃線和 _set 將表之間的操做鏈接起來
![](http://static.javashuo.com/static/loading.gif)
class UserProfile(models.Model): user_info = models.OneToOneField('UserInfo') username = models.CharField(max_length=64) password = models.CharField(max_length=64) def __unicode__(self): return self.username class UserInfo(models.Model): user_type_choice = ( (0, u'普通用戶'), (1, u'高級用戶'), ) user_type = models.IntegerField(choices=user_type_choice) name = models.CharField(max_length=32) email = models.CharField(max_length=32) address = models.CharField(max_length=128) def __unicode__(self): return self.name class UserGroup(models.Model): caption = models.CharField(max_length=64) user_info = models.ManyToManyField('UserInfo') def __unicode__(self): return self.caption class Host(models.Model): hostname = models.CharField(max_length=64) ip = models.GenericIPAddressField() user_group = models.ForeignKey('UserGroup') def __unicode__(self): return self.hostname 表結構實例
![](http://static.javashuo.com/static/loading.gif)
user_info_obj = models.UserInfo.objects.filter(id=1).first() print user_info_obj.user_type print user_info_obj.get_user_type_display() print user_info_obj.userprofile.password user_info_obj = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first() print user_info_obj.keys() print user_info_obj.values() 一對一操做
![](http://static.javashuo.com/static/loading.gif)
# 添加一對多 dic = { "hostname": "名字1", "ip": "192.168.1.1", "user_group_id": 1, # 加對象則爲"user_group" } models.Host.objects.create(**dic) # 正向查一對多 host_obj = models.Host.objects.all() print(type(host_obj), # <class 'django.db.models.query.QuerySet'> host_obj) # <QuerySet [<Host: 名字1>]> for item in host_obj: print(item.hostname) print(item.user_group.caption) print(item.user_group.user_info.values()) # <QuerySet [{'name': 'nick', 'user_type': 1, 'id': 1, 'email': '630571017@qq.com', 'address': '128號'}]> usergroup_obj = models.Host.objects.filter(user_group__caption='標題1') print(usergroup_obj) # 反向查一對多 usergroup_obj = models.UserGroup.objects.get(id=1) print(usergroup_obj.caption) ret = usergroup_obj.host_set.all() # 全部關於id=1的host print(ret) obj = models.UserGroup.objects.filter(host__ip='192.168.1.1').\ values('host__id', 'host__hostname') print(obj) # <QuerySet [{'host__id': 1, 'host__hostname': '名字1'}]> 一對多
![](http://static.javashuo.com/static/loading.gif)
user_info_obj = models.UserInfo.objects.get(name='nick') user_info_objs = models.UserInfo.objects.all() group_obj = models.UserGroup.objects.get(caption='CTO') group_objs = models.UserGroup.objects.all() # 添加數據 #group_obj.user_info.add(user_info_obj) #group_obj.user_info.add(*user_info_objs) # 刪除數據 #group_obj.user_info.remove(user_info_obj) #group_obj.user_info.remove(*user_info_objs) # 添加數據 #user_info_obj.usergroup_set.add(group_obj) #user_info_obj.usergroup_set.add(*group_objs) # 刪除數據 #user_info_obj.usergroup_set.remove(group_obj) #user_info_obj.usergroup_set.remove(*group_objs) # 獲取數據 #print group_obj.user_info.all() #print group_obj.user_info.all().filter(id=1) # 獲取數據 #print user_info_obj.usergroup_set.all() #print user_info_obj.usergroup_set.all().filter(caption='CTO') #print user_info_obj.usergroup_set.all().filter(caption='DBA') # 添加多對多 # userinfo_id_1 = models.UserInfo.objects.filter(id=1) # usergroup_id_1 = models.UserGroup.objects.filter(id=1).first() # usergroup_id_1.user_info.add(*userinfo_id_1) 多對多操做
擴展:
a、自定義上傳
![](http://static.javashuo.com/static/loading.gif)
def upload_file(request): if request.method == "POST": obj = request.FILES.get('fafafa') f = open(obj.name, 'wb') for chunk in obj.chunks(): f.write(chunk) f.close() return render(request, 'file.html') 示例
b、Form上傳文件實例
![](http://static.javashuo.com/static/loading.gif)
# HTML <form method="post" action="/view1/" enctype="multipart/form-data"> <input type="file" name="ExcelFile" id="id_ExcelFile" /> <input type="submit" value="提交" /> </form> # Form class FileForm(forms.Form): ExcelFile = forms.FileField() # Models from django.db import models class UploadFile(models.Model): userid = models.CharField(max_length = 30) file = models.FileField(upload_to = './upload/') date = models.DateTimeField(auto_now_add=True) # Views def UploadFile(request): uf = AssetForm.FileForm(request.POST,request.FILES) if uf.is_valid(): upload = models.UploadFile() upload.userid = 1 upload.file = uf.cleaned_data['ExcelFile'] upload.save() print upload.file
c、ajax上傳文件實例
![](http://static.javashuo.com/static/loading.gif)
<div> {{ up.ExcelFile }} <input type="button" id="submitj" value="提交" /> </div> <script src="/static/js/jquery-2.1.4.min.js"></script> <script> $('#submitj').bind("click",function () { var file = $('#id_ExcelFile')[0].files[0]; var form = new FormData(); form.append('ExcelFile', file); $.ajax({ type:'POST', url: '/view1/', data: form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success: function(arg){ console.log(arg); } }) }) </script> HTML
![](http://static.javashuo.com/static/loading.gif)
class FileForm(forms.Form): ExcelFile = forms.FileField()
![](http://static.javashuo.com/static/loading.gif)
from django.db import models class UploadFile(models.Model): userid = models.CharField(max_length = 30) file = models.FileField(upload_to = './upload/') date = models.DateTimeField(auto_now_add=True) Models
![](http://static.javashuo.com/static/loading.gif)
from study1 import forms def UploadFile(request): uf = AssetForm.FileForm(request.POST,request.FILES) if uf.is_valid(): upload = models.UploadFile() upload.userid = 1 upload.file = uf.cleaned_data['ExcelFile'] upload.save() print upload.file return render(request, 'file.html', locals()) View
7、中間件(MiddleWare)
django 中的中間件(middleware),在django中,中間件其實就是一個類,在請求到來和結束後,django會根據本身的規則在合適的時機執行中間件中相應的方法。
在django項目的settings模塊中,有一個 MIDDLEWARE_CLASSES 變量,其中每個元素就是一箇中間件,以下圖。
與mange.py在同一目錄下的文件夾 wupeiqi/middleware下的auth.py文件中的Authentication類
中間件中能夠定義五個方法,分別是:
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_template_response(self,request,response)
- process_exception(self, request, exception)
- process_response(self, request, response)
分析源碼得知前二個方法是從前日後執行的,後三個方法是從後往前執行的
因此前兩個方法是請求進來時要穿越的,然後三個方法是請求出去時要穿越的
一張圖告訴你中間件的運行流程
自定義中間件
一、建立中間件類
class Middle_Test(object): def process_request(self,request): pass def process_view(self, request, callback, callback_args, callback_kwargs): i =1 pass def process_exception(self, request, exception): pass def process_response(self, request, response): return response
二、註冊中間件
MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'sparks.middleware.auth.Middle_Test', )
8、 Form
django中的Form通常有兩種功能:
- 輸入html
- 驗證用戶輸入
![](http://static.javashuo.com/static/loading.gif)
#!/usr/bin/env python # -*- coding:utf-8 -*- import re from django import forms from django.core.exceptions import ValidationError def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): raise ValidationError('手機號碼格式錯誤') class PublishForm(forms.Form): user_type_choice = ( (0, u'普通用戶'), (1, u'高級用戶'), ) user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice, attrs={'class': "form-control"})) title = forms.CharField(max_length=20, min_length=5, error_messages={'required': u'標題不能爲空', 'min_length': u'標題最少爲5個字符', 'max_length': u'標題最多爲20個字符'}, widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'標題5-20個字符'})) memo = forms.CharField(required=False, max_length=256, widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'詳細描述', 'rows': 3})) phone = forms.CharField(validators=[mobile_validate, ], error_messages={'required': u'手機不能爲空'}, widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'手機號碼'})) email = forms.EmailField(required=False, error_messages={'required': u'郵箱不能爲空','invalid': u'郵箱格式錯誤'}, widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'})) Form
![](http://static.javashuo.com/static/loading.gif)
def publish(request): ret = {'status': False, 'data': '', 'error': '', 'summary': ''} if request.method == 'POST': request_form = PublishForm(request.POST) if request_form.is_valid(): request_dict = request_form.clean() print request_dict ret['status'] = True else: error_msg = request_form.errors.as_json() ret['error'] = json.loads(error_msg) return HttpResponse(json.dumps(ret)) 示例
利用Form還能夠自動生成前端的input標籤:
![](http://static.javashuo.com/static/loading.gif)
from app01 import models from django import forms class Form1(forms.Form): user = forms.CharField( widget=forms.TextInput(attrs={'class':'c1'}), # 給標籤添加屬性 error_messages={'required':'用戶名不能爲空'}, # 自定義錯誤輸出 ) pwd = forms.CharField(max_length=4, min_length=2) email = forms.EmailField(error_messages={'required':'郵箱不能爲空', 'invalid':'郵箱格式錯誤'}) memo = forms.CharField( widget=forms.Textarea() ) # user_type_choice = ( # (0, '普通用戶'), # (1, '高級用戶'), # ) user_type_choice = models.BookType.objects.values_list("id", "caption") # 這樣並不能跟數據庫實時同步,由於靜態字段不更新 book_type = forms.CharField( widget=forms.widgets.Select(choices=user_type_choice) ) def __init__(self, *args, **kwargs): super(Form1, self).__init__(*args, **kwargs) # 讓選項框跟數據庫進行實時聯動,解決上一行註釋的問題 self.fields['book_type'] = forms.CharField( widget=forms.widgets.Select(choices=models.BookType.objects.values_list("id", "caption")) ) form.py
![](http://static.javashuo.com/static/loading.gif)
def form1(request): if request.method == "POST": # 獲取請求作驗證 f = Form1(request.POST) if f.is_valid(): print(f.cleaned_data) else: pass # print(f.errors['user'][0]) # print(f.errors['pwd'][0]) return render(request, "form1.html", {'error': f.errors, 'form':f}) else: f = Form1() return render(request, 'form1.html',{'form':f}) views.py
![](http://static.javashuo.com/static/loading.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .input-group{ position: relative; padding: 23px; } .input-group input{ width: 200px; display: inline-block; } .input-group span{ display: inline-block; position: absolute; height: 20px; background-color:coral; color: white; bottom: 1px; left: 22px; width: 204px; } </style> </head> <body> <div> <form action="/form/" method="post"> <div class="input-group"> {# <input type="text" name="user"/>#} {{ form.user }} {% if error.user.0 %} <span>{{ error.user.0 }}</span> {% endif %} </div> <div class="input-group"> {# <input type="text" name="pwd"/>#} {{ form.pwd }} {% if error.pwd.0 %} <span>{{ error.pwd.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.email }} {% if error.email.0 %} <span>{{ error.email.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.memo }} {% if error.memo.0 %} <span>{{ error.memo.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.book_type }} {% if error.book_type.0 %} <span>{{ error.book_type.0 }}</span> {% endif %} </div> <input type="submit" value="提交"/> </form> </div> </body> </html> form1.html
擴展:ModelForm
在使用Model和Form時,都須要對字段進行定義並指定類型,經過ModelForm則能夠省去From中字段的定義
![](http://static.javashuo.com/static/loading.gif)
class AdminModelForm(forms.ModelForm): class Meta: model = models.Admin #fields = '__all__' fields = ('username', 'email') widgets = { 'email' : forms.PasswordInput(attrs={'class':"alex"}), } ModelForm
9、 認證系統(auth)
auth模塊是Django提供的標準權限管理系統,能夠提供用戶身份認證, 用戶組管理,而且能夠和admin模塊配合使用.
在INSTALLED_APPS中添加'django.contrib.auth'使用該APP, auth模塊默認啓用.
model
from django.contrib.auth.models import User # 數據庫中該表名爲auth_user. CREATE TABLE "auth_user" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "password" varchar(128) NOT NULL, "last_login" datetime NULL, "is_superuser" bool NOT NULL, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL, "email" varchar(254) NOT NULL, "is_staff" bool NOT NULL, "is_active" bool NOT NULL, "date_joined" datetime NOT NULL, "username" varchar(30) NOT NULL UNIQUE )
新建用戶
user = User.objects.create_user(username, email, password) user.save() # 不存儲用戶密碼明文而是存儲一個Hash值
認證用戶
from django.contrib.auth import authenticate user = authenticate(username=username, password=password) # 認證用戶的密碼是否有效, 如有效則返回表明該用戶的user對象, 若無效則返回None. # 該方法不檢查is_active標誌位.
修改密碼
user.set_password(new_password) # 如下實例爲先認證經過後才能夠修改密碼 user = auth.authenticate(username=username, password=old_password) if user is not None: user.set_password(new_password) user.save()
登陸
from django.contrib.auth import login # login向session中添加SESSION_KEY, 便於對用戶進行跟蹤: 'login(request, user)' # login不進行認證,也不檢查is_active標誌位 # 實例 user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user)
退出登陸
# logout會移除request中的user信息, 並刷新session from django.contrib.auth import logout def logout_view(request): logout(request)
只容許登陸的用戶訪問
@login_required
修飾器修飾的view函數會先經過session key檢查是否登陸, 已登陸用戶能夠正常的執行操做, 未登陸用戶將被重定向到login_url
指定的位置.
若未指定login_url參數, 則重定向到settings.LOGIN_URL
from django.contrib.auth.decorators import login_required @login_required(login_url='/accounts/login/') def userinfo(request): ... # settings 配置 LOGIN_URL = '/index/' # views @login_required def userinfo(request): ...
10、 跨站請求僞造(csrf)
django爲用戶實現防止跨站請求僞造的功能,經過中間件 django.middleware.csrf.CsrfViewMiddleware 來完成。而對於django中設置防跨站請求僞造功能有分爲全局和局部。
全局:
中間件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置全局中間件。
- @csrf_exempt,取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
在Django1.10中,爲了防止BREACH攻擊,對cookie-form類型的csrf作了一點改進,即在cookie和form中的token值是不相同的
應用
一、普通表單
veiw中設置返回值: return render(request, 'xxx.html', data) html中設置Token: {% csrf_token %}
二、Ajax
對於傳統的form,能夠經過表單的方式將token再次發送到服務端,而對於ajax的話,使用以下方式。
![](http://static.javashuo.com/static/loading.gif)
# view.py from django.template.context import RequestContext # Create your views here. def test(request): if request.method == 'POST': print request.POST return HttpResponse('ok') return render_to_response('app01/test.html',context_instance=RequestContext(request)) view.py
![](http://static.javashuo.com/static/loading.gif)
# text.html <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> {% csrf_token %} <input type="button" onclick="Do();" value="Do it"/> <script src="/static/plugin/jquery/jquery-1.8.0.js"></script> <script src="/static/plugin/jquery/jquery.cookie.js"></script> <script type="text/javascript"> var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); function Do(){ $.ajax({ url:"/app01/test/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script> </body> </html> text.html
更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
11、 分頁
1. Django內置分頁
![](http://static.javashuo.com/static/loading.gif)
from django.shortcuts import render from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger L = [] for i in range(999): L.append(i) def index(request): current_page = request.GET.get('p') paginator = Paginator(L, 10) # per_page: 每頁顯示條目數量 # count: 數據總個數 # num_pages:總頁數 # page_range:總頁數的索引範圍,如: (1,10),(1,200) # page: page對象 try: posts = paginator.page(current_page) # has_next 是否有下一頁 # next_page_number 下一頁頁碼 # has_previous 是否有上一頁 # previous_page_number 上一頁頁碼 # object_list 分頁以後的數據列表 # number 當前頁 # paginator paginator對象 except PageNotAnInteger: posts = paginator.page(1) except EmptyPage: posts = paginator.page(paginator.num_pages) return render(request, 'index.html', {'posts': posts}) views.py
![](http://static.javashuo.com/static/loading.gif)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <ul> {% for item in posts %} <li>{{ item }}</li> {% endfor %} </ul> <div class="pagination"> <span class="step-links"> {% if posts.has_previous %} <a href="?p={{ posts.previous_page_number }}">Previous</a> {% endif %} <span class="current"> Page {{ posts.number }} of {{ posts.paginator.num_pages }}. </span> {% if posts.has_next %} <a href="?p={{ posts.next_page_number }}">Next</a> {% endif %} </span> </div> </body> </html> Html
![](http://static.javashuo.com/static/loading.gif)
from django.shortcuts import render from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger class CustomPaginator(Paginator): def __init__(self, current_page, max_pager_num, *args, **kwargs): """ :param current_page: 當前頁 :param max_pager_num:最多顯示的頁碼個數 :param args: :param kwargs: :return: """ self.current_page = int(current_page) self.max_pager_num = max_pager_num super(CustomPaginator, self).__init__(*args, **kwargs) def page_num_range(self): # 當前頁面 # self.current_page # 總頁數 # self.num_pages # 最多顯示的頁碼個數 # self.max_pager_num print(1) if self.num_pages < self.max_pager_num: return range(1, self.num_pages + 1) print(2) part = int(self.max_pager_num / 2) if self.current_page - part < 1: return range(1, self.max_pager_num + 1) print(3) if self.current_page + part > self.num_pages: return range(self.num_pages + 1 - self.max_pager_num, self.num_pages + 1) print(4) return range(self.current_page - part, self.current_page + part + 1) L = [] for i in range(999): L.append(i) def index(request): current_page = request.GET.get('p') paginator = CustomPaginator(current_page, 11, L, 10) # per_page: 每頁顯示條目數量 # count: 數據總個數 # num_pages:總頁數 # page_range:總頁數的索引範圍,如: (1,10),(1,200) # page: page對象 try: posts = paginator.page(current_page) # has_next 是否有下一頁 # next_page_number 下一頁頁碼 # has_previous 是否有上一頁 # previous_page_number 上一頁頁碼 # object_list 分頁以後的數據列表 # number 當前頁 # paginator paginator對象 except PageNotAnInteger: posts = paginator.page(1) except EmptyPage: posts = paginator.page(paginator.num_pages) return render(request, 'index.html', {'posts': posts}) 擴展內置分頁:views.py
![](http://static.javashuo.com/static/loading.gif)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <ul> {% for item in posts %} <li>{{ item }}</li> {% endfor %} </ul> <div class="pagination"> <span class="step-links"> {% if posts.has_previous %} <a href="?p={{ posts.previous_page_number }}">Previous</a> {% endif %} {% for i in posts.paginator.page_num_range %} <a href="?p={{ i }}">{{ i }}</a> {% endfor %} {% if posts.has_next %} <a href="?p={{ posts.next_page_number }}">Next</a> {% endif %} </span> <span class="current"> Page {{ posts.number }} of {{ posts.paginator.num_pages }}. </span> </div> </body> </html> 擴展內置分頁:Html
2. 自定義分頁
分頁功能在每一個網站都是必要的,對於分頁來講,其實就是根據用戶的輸入計算出應該在數據庫表中的起始位置。
一、設定每頁顯示數據條數
二、用戶輸入頁碼(第一頁、第二頁...)
三、根據設定的每頁顯示條數和當前頁碼,計算出須要取數據表的起始位置
四、在數據表中根據起始位置取值,頁面上輸出數據
需求又來了,須要在頁面上顯示分頁的頁面。如:[上一頁][1][2][3][4][5][下一頁]
一、設定每頁顯示數據條數
二、用戶輸入頁碼(第一頁、第二頁...)
三、設定顯示多少頁號
四、獲取當前數據總條數
五、根據設定顯示多少頁號和數據總條數計算出,總頁數
六、根據設定的每頁顯示條數和當前頁碼,計算出須要取數據表的起始位置
七、在數據表中根據起始位置取值,頁面上輸出數據
八、輸出分頁html,如:[上一頁][1][2][3][4][5][下一頁]
![](http://static.javashuo.com/static/loading.gif)
#!/usr/bin/env python # _*_coding:utf-8_*_ from django.utils.safestring import mark_safe class PageInfo(object): def __init__(self,current,totalItem,peritems=5): self.__current=current self.__peritems=peritems self.__totalItem=totalItem def From(self): return (self.__current-1)*self.__peritems def To(self): return self.__current*self.__peritems def TotalPage(self): #總頁數 result=divmod(self.__totalItem,self.__peritems) if result[1]==0: return result[0] else: return result[0]+1 def Custompager(baseurl,currentPage,totalpage): #基礎頁,當前頁,總頁數 perPager=11 #總頁數<11 #0 -- totalpage #總頁數>11 #當前頁大於5 currentPage-5 -- currentPage+5 #currentPage+5是否超過總頁數,超過總頁數,end就是總頁數 #當前頁小於5 0 -- 11 begin=0 end=0 if totalpage <= 11: begin=0 end=totalpage else: if currentPage>5: begin=currentPage-5 end=currentPage+5 if end > totalpage: end=totalpage else: begin=0 end=11 pager_list=[] if currentPage<=1: first="<a href=''>首頁</a>" else: first="<a href='%s%d'>首頁</a>" % (baseurl,1) pager_list.append(first) if currentPage<=1: prev="<a href=''>上一頁</a>" else: prev="<a href='%s%d'>上一頁</a>" % (baseurl,currentPage-1) pager_list.append(prev) for i in range(begin+1,end+1): if i == currentPage: temp="<a href='%s%d' class='selected'>%d</a>" % (baseurl,i,i) else: temp="<a href='%s%d'>%d</a>" % (baseurl,i,i) pager_list.append(temp) if currentPage>=totalpage: next="<a href='#'>下一頁</a>" else: next="<a href='%s%d'>下一頁</a>" % (baseurl,currentPage+1) pager_list.append(next) if currentPage>=totalpage: last="<a href=''>末頁</a>" else: last="<a href='%s%d'>末頁</a>" % (baseurl,totalpage) pager_list.append(last) result=''.join(pager_list) return mark_safe(result) #把字符串轉成html語言 分頁實例
總結,分頁時須要作三件事:
- 建立處理分頁數據的類
- 根據分頁數據獲取數據
- 輸出分頁HTML,即:[上一頁][1][2][3][4][5][下一頁]
12、 Cookie
1. 獲取Cookie:
request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None) 參數: default: 默認值 salt: 加密鹽 max_age: 後臺控制過時時間
2. 設置Cookie:
rep = HttpResponse(...) 或 rep = render(request, ...) rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密鹽',...) 參數: key, 鍵 value='', 值 max_age=None, 超時時間 expires=None, 超時時間(IE requires expires, so set it if hasn't been already.) path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:跟路徑的cookie能夠被任何url的頁面訪問 domain=None, Cookie生效的域名 secure=False, https傳輸 httponly=False 只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)
因爲cookie保存在客戶端的電腦上,因此,JavaScript和jquery也能夠操做cookie。
<script src='/static/js/jquery.cookie.js'></script> $.cookie("list_pager_num", 30,{ path: '/' });
十3、 Session
Django中默認支持Session,其內部提供了5種類型的Session供開發者使用:
- 數據庫(默認)
- 緩存
- 文件
- 緩存+數據庫
- 加密cookie
一、數據庫Session
![](http://static.javashuo.com/static/loading.gif)
Django默認支持Session,而且默認是將Session數據存儲在數據庫中,即:django_session 表中。 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認) SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時(默認) SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改以後才保存(默認) b. 使用 def index(request): # 獲取、設置、刪除Session中數據 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設置 del request.session['k1'] # 全部 鍵、值、鍵值對 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 用戶session的隨機字符串 request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除 request.session.clear_expired() # 檢查 用戶session的隨機字符串 在數據庫中是否 request.session.exists("session_key") # 刪除當前用戶的全部Session數據 request.session.delete("session_key") ...
二、緩存Session
![](http://static.javashuo.com/static/loading.gif)
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時 SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改以後才保存 b. 使用 同上
三、文件Session
![](http://static.javashuo.com/static/loading.gif)
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時 SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改以後才保存 b. 使用 同上
四、緩存+數據庫Session
![](http://static.javashuo.com/static/loading.gif)
數據庫用於作持久化,緩存用於提升效率 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 b. 使用 同上
五、加密cookie Session
![](http://static.javashuo.com/static/loading.gif)
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 b. 使用 同上
跟數據庫的操做同樣,在Django中不一樣緩存方式的使用方法是一致的,想要改變緩存的類型只須要改變上述相應配置便可。
擴展:Session用戶驗證(裝飾器)
def login(func): def wrap(request, *args, **kwargs): # 若是未登錄,跳轉到指定頁面 if request.path == '/test/': return redirect('http://www.baidu.com') return func(request, *args, **kwargs) return wrap
十4、 緩存
因爲Django是動態網站,全部每次請求均會去數據進行相應的操做,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個views的返回值保存至內存或者memcache中,5分鐘內再有人來訪問時,則再也不去執行view中的操做,而是直接從內存或者Redis中以前緩存的內容拿到,並返回。
Django中提供了6種緩存方式:
- 開發調試
- 內存
- 文件
- 數據庫
- Memcache緩存(python-memcached模塊)
- Memcache緩存(pylibmc模塊)
和數據庫相似,緩存的具體操做都是同樣的,使用不一樣的方式只須要將配置改掉便可
一、配置
a、開發調試
![](http://static.javashuo.com/static/loading.gif)
# 此爲開始調試用,實際內部不作任何操做 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎 'TIMEOUT': 300, # 緩存超時時間(默認300,None表示永不過時,0表示當即過時) 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大緩存個數(默認300) 'CULL_FREQUENCY': 3, # 緩存到達最大個數以後,剔除緩存個數的比例,即:1/CULL_FREQUENCY(默認3) }, 'KEY_PREFIX': '', # 緩存key的前綴(默認空) 'VERSION': 1, # 緩存key的版本(默認1) 'KEY_FUNCTION' 函數名 # 生成key的函數(默認函數會生成爲:【前綴:版本:key】) } } # 自定義key def default_key_func(key, key_prefix, version): """ Default function to generate keys. Constructs the key used by all other methods. By default it prepends the `key_prefix'. KEY_FUNCTION can be used to specify an alternate function with custom key making behavior. """ return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func): """ Function to decide which key function to use. Defaults to ``default_key_func``. """ if key_func is not None: if callable(key_func): return key_func else: return import_string(key_func) return default_key_func
b、內存
![](http://static.javashuo.com/static/loading.gif)
# 此緩存將內容保存至內存的變量中 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake', } } # 注:其餘配置同開發調試版本
c、文件
![](http://static.javashuo.com/static/loading.gif)
# 此緩存將內容保存至文件 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/django_cache', } } # 注:其餘配置同開發調試版本
d、數據庫
![](http://static.javashuo.com/static/loading.gif)
# 此緩存將內容保存至數據庫 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # 數據庫表 } } # 注:執行建立表命令 python manage.py createcachetable
e、Memcache緩存(python-memcached模塊)
![](http://static.javashuo.com/static/loading.gif)
# 此緩存使用python-memcached模塊鏈接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'unix:/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } }
f、Memcache緩存(pylibmc模塊)
![](http://static.javashuo.com/static/loading.gif)
# 此緩存使用pylibmc模塊鏈接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } }
二、應用
a. 全站使用
![](http://static.javashuo.com/static/loading.gif)
使用中間件,通過一系列的認證等操做,若是內容在緩存中存在,則使用FetchFromCacheMiddleware獲取內容並返回給用戶,當返回給用戶以前,判斷緩存中是否已經存在,若是不存在則UpdateCacheMiddleware會將緩存保存至緩存,從而實現全站緩存 MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', # 其餘中間件... 'django.middleware.cache.FetchFromCacheMiddleware', ] CACHE_MIDDLEWARE_ALIAS = "" CACHE_MIDDLEWARE_SECONDS = "" CACHE_MIDDLEWARE_KEY_PREFIX = ""
b. 單獨視圖緩存
![](http://static.javashuo.com/static/loading.gif)
方式一: from django.views.decorators.cache import cache_page @cache_page(60 * 15) def my_view(request): ... 方式二: from django.views.decorators.cache import cache_page urlpatterns = [ url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)), ]
c、局部視圖使用
![](http://static.javashuo.com/static/loading.gif)
a. 引入TemplateTag {% load cache %} b. 使用緩存 {% cache 5000 緩存key %} 緩存內容 {% endcache %}
注:若是出現多個url匹配同一個view函數的狀況,緩存機制會根據每個不一樣的url作單獨的緩存
更多:猛擊這裏
十5、 序列化
關於Django中的序列化主要應用在將數據庫中檢索的數據返回給客戶端用戶,特別的Ajax請求通常返回的爲Json格式。
1. serializers
from django.core import serializers ret = models.BookType.objects.all() data = serializers.serialize("json", ret)
2. json.dumps
import json #ret = models.BookType.objects.all().values('caption') ret = models.BookType.objects.all().values_list('caption') ret=list(ret) result = json.dumps(ret)
因爲json.dumps時沒法處理datetime日期,因此能夠經過自定義處理器來作擴展,如:
![](http://static.javashuo.com/static/loading.gif)
import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime): return o.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field, date): return o.strftime('%Y-%m-%d') else: return json.JSONEncoder.default(self, field) # ds = json.dumps(d, cls=JsonCustomEncoder) 自定義示例
十6、 信號
Django中提供了「信號調度」,用於在框架執行操做時解耦。通俗來說,就是一些動做發生的時候,信號容許特定的發送者去提醒一些接受者。
一、Django內置信號
Model signals pre_init # django的modal執行其構造方法前,自動觸發 post_init # django的modal執行其構造方法後,自動觸發 pre_save # django的modal對象保存前,自動觸發 post_save # django的modal對象保存後,自動觸發 pre_delete # django的modal對象刪除前,自動觸發 post_delete # django的modal對象刪除後,自動觸發 m2m_changed # django的modal中使用m2m字段操做第三張表(add,remove,clear)先後,自動觸發 class_prepared # 程序啓動時,檢測已註冊的app中modal類,對於每個類,自動觸發 Management signals pre_migrate # 執行migrate命令前,自動觸發 post_migrate # 執行migrate命令後,自動觸發 Request/response signals request_started # 請求到來前,自動觸發 request_finished # 請求結束後,自動觸發 got_request_exception # 請求異常後,自動觸發 Test signals setting_changed # 使用test測試修改配置文件時,自動觸發 template_rendered # 使用test測試渲染模板時,自動觸發 Database Wrappers connection_created # 建立數據庫鏈接時,自動觸發
對於Django內置的信號,僅需註冊指定信號,當程序執行相應操做時,自動觸發註冊函數:
![](http://static.javashuo.com/static/loading.gif)
from django.core.signals import request_finished from django.core.signals import request_started from django.core.signals import got_request_exception from django.db.models.signals import class_prepared from django.db.models.signals import pre_init, post_init from django.db.models.signals import pre_save, post_save from django.db.models.signals import pre_delete, post_delete from django.db.models.signals import m2m_changed from django.db.models.signals import pre_migrate, post_migrate from django.test.signals import setting_changed from django.test.signals import template_rendered from django.db.backends.signals import connection_created def callback(sender, **kwargs): print("xxoo_callback") print(sender,kwargs) xxoo.connect(callback) # xxoo指上述導入的內容
二、自定義信號
a. 定義並註冊信號
# 自定製信號 import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]) def callback(sender, **kwargs): print("self-define") print(sender, kwargs) pizza_done.connect(callback)
b. 觸發信號
from 路徑 import pizza_done pizza_done.send(sender='seven',toppings=123, size=456)
因爲內置信號的觸發者已經集成到Django中,因此其會自動調用,而對於自定義信號則須要開發者在任意位置觸發。
更多:猛擊這裏
十7、admin
django amdin是django提供的一個後臺管理頁面,改管理頁面提供完善的html和css,使得你在經過Model建立完數據庫表以後,就能夠對數據進行增刪改查,而使用django admin 則須要如下步驟:
- 建立後臺管理員
- 配置url
- 註冊和配置django admin後臺管理頁面
注:不建議新手常用admin,會造成依賴,核心的是model模塊的操做!
一、建立後臺管理員
python manage.py createsuperuser
二、配置後臺管理url(默認已配)
url(r'^admin/', include(admin.site.urls))
三、註冊和配置django admin 後臺管理頁面
a、在admin中執行以下配置
![](http://static.javashuo.com/static/loading.gif)
from django.contrib import admin from app01 import models admin.site.register(models.UserType) admin.site.register(models.UserInfo) admin.site.register(models.UserGroup) admin.site.register(models.Asset)
b、設置數據表名稱
![](http://static.javashuo.com/static/loading.gif)
class UserType(models.Model): name = models.CharField(max_length=50) class Meta: verbose_name = '用戶類型' verbose_name_plural = '用戶類型'
c、打開表以後,設定默認顯示,須要在model中做以下配置
![](http://static.javashuo.com/static/loading.gif)
class UserType(models.Model): name = models.CharField(max_length=50) def __unicode__(self): # python3 is __str__(self) return self.name
d、爲數據表添加搜索功能
![](http://static.javashuo.com/static/loading.gif)
from django.contrib import admin from app01 import models class UserInfoAdmin(admin.ModelAdmin): list_display = ('username', 'password', 'email') search_fields = ('username', 'email') admin.site.register(models.UserType) admin.site.register(models.UserInfo,UserInfoAdmin) admin.site.register(models.UserGroup) admin.site.register(models.Asset)
e、添加快速過濾
![](http://static.javashuo.com/static/loading.gif)
from django.contrib import admin from app01 import models class UserInfoAdmin(admin.ModelAdmin): list_display = ('username', 'password', 'email') search_fields = ('username', 'email') list_filter = ('username', 'email') admin.site.register(models.UserType) admin.site.register(models.UserInfo,UserInfoAdmin) admin.site.register(models.UserGroup) admin.site.register(models.Asset)
更多:https://docs.djangoproject.com/en/1.11/ref/contrib/admin/
後續更新中……