Python的WEB框架有Django、Tornado、Flask 等多種,Django相較與其他WEB框架其優勢為:大而全,框架本身集成了ORM、模型綁定、模板引擎、緩存、Session等諸多功能。
本文將以下方面帶大家全面了解Django框架,筆者使用的版本為1.10.
-
流程
- 基本配置
- 路由系統
- 視圖view
- 模板
- Model
- 中間件
- Form
- 認證系統
- CSRF
- 分頁
- Cookie
- Seesion
- 緩存
- 序列化
- 信號
- admin
一、 Django流程介紹
MVC是眾所周知的模式,即:將應用程序分解成三個組成部分:model(模型),view(視圖),和 controller(控制 器)。其中:
M——管理應用程序的狀態(通常存儲到數據庫中),並約束改變狀態的行為(或者叫做“業務規則”)。
C——接受外部用戶的操作,根據操作訪問模型獲取數據,並調用“視圖”顯示這些數據。控制器是將“模型”和“視圖”隔離,並成為二者之間的聯系紐帶。
V——負責把數據格式化后呈現給用戶。
Django也是一個MVC框架。但是在Django中,控制器接受用戶輸入的部分由框架自行處理,所以 Django 里更關注的是模型(Model)、模板(Template)和視圖(Views),稱為 MTV模式:
M 代表模型(Model),即數據存取層。 該層處理與數據相關的所有事務: 如何存取、如何驗證有效性、包含哪些行為以及數據之間的關系等。
T 代表模板(Template),即表現層。 該層處理與表現相關的決定: 如何在頁面或其他類型文檔中進行顯示。
V 代表視圖(View),即業務邏輯層。 該層包含存取模型及調取恰當模板的相關邏輯。 你可以把它看作模型與模板之間的橋梁。
二、 Django 基本配置
1. 創建django程序
- 終端命令:django-admin startproject sitename (在當前目錄下創建一個Django程序)
- IDE創建Django程序時,本質上都是自動執行上述命令
其他常用命令:
python manage.py runserver ip:port (啟動服務器,默認ip和端口為http://127.0.0.1:8000/)
python manage.py startapp appname (新建 app)
python manage.py syncdb (同步數據庫命令,Django 1.7及以上版本需要用以下的命令)
python manage.py makemigrations (顯示並記錄所有數據的改動)
python manage.py migrate (將改動更新到數據庫)
python manage.py createsuperuser (創建超級管理員)
python manage.py dbshell (數據庫命令行)
python manage.py (查看命令列表)
2. 程序目錄
3. 配置文件
a、數據庫
支持SQLite 3(默認)、PostgreSQL 、MySQL、Oracle數據庫的操作

# 默認是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、靜態文件添加

# 首先在項目根目錄下創建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>
三、 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值.
我們來看一個例子:

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> #######################
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
值由正則表達式捕獲。
四、 Django Views(視圖函數)
http請求中產生兩個核心對象:
http請求:HttpRequest對象
http響應:HttpResponse對象
1. HttpRequest對象
當請求一個頁面時,Django 創建一個 HttpRequest
對象包含原數據的請求。然后 Django 加載適當的視圖,通過 HttpRequest
作為視圖函數的第一個參數。每個視圖負責返回一個HttpResponse
目標。

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 – 服務器的端口(一個字符串)。
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')
五、 模板
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/
六、 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()

1、null=True 數據庫中字段是否可以為空 2、blank=True django的 Admin 中添加數據時是否可允許空值 3、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中字段的顯示名稱 9、name|db_column 數據庫中的字段名稱 10、unique=True 不允許重復 11、db_index = True 數據庫索引 12、editable=True 在Admin里是否可編輯 13、error_messages=None 錯誤提示 14、auto_created=False 自動創建 15、help_text 在Admin中提示幫助信息 16、validators=[] 17、upload-to

1、models.AutoField 自增列 = int(11) 如果沒有的話,默認會生成一個名稱為 id 的列,如果要顯示的自定義一個自增列,必須將給列設置為主鍵 primary_key=True。 2、models.CharField 字符串字段 必須 max_length 參數 3、models.BooleanField 布爾類型=tinyint(1) 不能為空,Blank=True 4、models.ComaSeparatedIntegerField 用逗號分割的數字=varchar 繼承CharField,所以必須 max_lenght 參數 5、models.DateField 日期類型 date 對於參數,auto_now = True 則每次更新都會更新這個時間;auto_now_add 則只是第一次創建添加,之后的更新不再改變。 6、models.DateTimeField 日期類型 datetime 同DateField的參數 7、models.Decimal 十進制小數類型 = decimal 必須指定整數位max_digits和小數位decimal_places 8、models.EmailField 字符串類型(正則表達式郵箱) =varchar 對字符串進行正則表達式 9、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、ipv4、ipv6 驗證時,會根據設置報錯 14、models.NullBooleanField 允許為空的布爾類型 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 減號、下划線、字母、數字 18、models.SmallIntegerField 數字 數據庫中的字段有:tinyint、smallint、int、bigint 19、models.TextField 字符串=longtext 20、models.TimeField 時間 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字符串,地址正則表達式 22、models.BinaryField 二進制 23、models.ImageField 圖片 24、models.FilePathField 文件

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/

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列數據

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、基本操作

# 增 # # 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、進階操作(了不起的雙下划線)
利用雙下划線將字段和對應的操作連接起來

# 獲取個數 # # 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等於11、22、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、其他操作

# 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 將表之間的操作連接起來

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

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()

# 添加一對多 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'}]>

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、自定義上傳

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上傳文件實例

# 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上傳文件實例

<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>

class FileForm(forms.Form): ExcelFile = forms.FileField()

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)

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())
七、中間件(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)
分析源碼得知前二個方法是從前往后執行的,后三個方法是從后往前執行的
所以前兩個方法是請求進來時要穿越的,而后三個方法是請求出去時要穿越的
一張圖告訴你中間件的運行流程
自定義中間件
1、創建中間件類
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
2、注冊中間件
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', )
八、 Form
django中的Form一般有兩種功能:
- 輸入html
- 驗證用戶輸入

#!/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'郵箱'}))

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標簽:

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")) )

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})

<!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>
擴展:ModelForm
在使用Model和Form時,都需要對字段進行定義並指定類型,通過ModelForm則可以省去From中字段的定義

class AdminModelForm(forms.ModelForm): class Meta: model = models.Admin #fields = '__all__' fields = ('username', 'email') widgets = { 'email' : forms.PasswordInput(attrs={'class':"alex"}), }
九、 認證系統(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): ...
十、 跨站請求偽造(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值是不相同的
應用
1、普通表單
veiw中設置返回值: return render(request, 'xxx.html', data) html中設置Token: {% csrf_token %}
2、Ajax
對於傳統的form,可以通過表單的方式將token再次發送到服務端,而對於ajax的話,使用如下方式。

# 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))

# 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>
更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
十一、 分頁
1. Django內置分頁

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})

<!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>

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})

<!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>
2. 自定義分頁
分頁功能在每個網站都是必要的,對於分頁來說,其實就是根據用戶的輸入計算出應該在數據庫表中的起始位置。
1、設定每頁顯示數據條數
2、用戶輸入頁碼(第一頁、第二頁...)
3、根據設定的每頁顯示條數和當前頁碼,計算出需要取數據表的起始位置
4、在數據表中根據起始位置取值,頁面上輸出數據
需求又來了,需要在頁面上顯示分頁的頁面。如:[上一頁][1][2][3][4][5][下一頁]
1、設定每頁顯示數據條數
2、用戶輸入頁碼(第一頁、第二頁...)
3、設定顯示多少頁號
4、獲取當前數據總條數
5、根據設定顯示多少頁號和數據總條數計算出,總頁數
6、根據設定的每頁顯示條數和當前頁碼,計算出需要取數據表的起始位置
7、在數據表中根據起始位置取值,頁面上輸出數據
8、輸出分頁html,如:[上一頁][1][2][3][4][5][下一頁]

#!/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][下一頁]
十二、 Cookie
1. 獲取Cookie:
1
2
3
4
5
6
|
request.COOKIES[
'key'
]
request.get_signed_cookie(key, default
=
RAISE_ERROR, salt
=
'', max_age
=
None
)
參數:
default: 默認值
salt: 加密鹽
max_age: 后台控制過期時間
|
2. 設置Cookie:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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。
1
2
|
<script src
=
'/static/js/jquery.cookie.js'
><
/
script>
$.cookie(
"list_pager_num"
,
30
,{ path:
'/'
});
|
十三、 Session
Django中默認支持Session,其內部提供了5種類型的Session供開發者使用:
- 數據庫(默認)
- 緩存
- 文件
- 緩存+數據庫
- 加密cookie
1、數據庫Session

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") ...
2、緩存Session

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. 使用 同上
3、文件Session

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. 使用 同上
4、緩存+數據庫Session

數據庫用於做持久化,緩存用於提高效率 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 b. 使用 同上
5、加密cookie Session

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
十四、 緩存
由於Django是動態網站,所有每次請求均會去數據進行相應的操作,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個views的返回值保存至內存或者memcache中,5分鍾內再有人來訪問時,則不再去執行view中的操作,而是直接從內存或者Redis中之前緩存的內容拿到,並返回。
Django中提供了6種緩存方式:
- 開發調試
- 內存
- 文件
- 數據庫
- Memcache緩存(python-memcached模塊)
- Memcache緩存(pylibmc模塊)
和數據庫類似,緩存的具體操作都是一樣的,使用不同的方式只需要將配置改掉即可
1、配置
a、開發調試

# 此為開始調試用,實際內部不做任何操作 # 配置: 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、內存

# 此緩存將內容保存至內存的變量中 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake', } } # 注:其他配置同開發調試版本
c、文件

# 此緩存將內容保存至文件 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/django_cache', } } # 注:其他配置同開發調試版本
d、數據庫

# 此緩存將內容保存至數據庫 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # 數據庫表 } } # 注:執行創建表命令 python manage.py createcachetable
e、Memcache緩存(python-memcached模塊)

# 此緩存使用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模塊)

# 此緩存使用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', ] } }
2、應用
a. 全站使用

使用中間件,經過一系列的認證等操作,如果內容在緩存中存在,則使用FetchFromCacheMiddleware獲取內容並返回給用戶,當返回給用戶之前,判斷緩存中是否已經存在,如果不存在則UpdateCacheMiddleware會將緩存保存至緩存,從而實現全站緩存 MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', # 其他中間件... 'django.middleware.cache.FetchFromCacheMiddleware', ] CACHE_MIDDLEWARE_ALIAS = "" CACHE_MIDDLEWARE_SECONDS = "" CACHE_MIDDLEWARE_KEY_PREFIX = ""
b. 單獨視圖緩存

方式一: 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、局部視圖使用

a. 引入TemplateTag {% load cache %} b. 使用緩存 {% cache 5000 緩存key %} 緩存內容 {% endcache %}
注:如果出現多個url匹配同一個view函數的情況,緩存機制會根據每一個不同的url做單獨的緩存
更多:猛擊這里
十五、 序列化
關於Django中的序列化主要應用在將數據庫中檢索的數據返回給客戶端用戶,特別的Ajax請求一般返回的為Json格式。
1. serializers
1
2
3
4
5
|
from
django.core
import
serializers
ret
=
models.BookType.objects.
all
()
data
=
serializers.serialize(
"json"
, ret)
|
2. json.dumps
1
2
3
4
5
6
7
8
|
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日期,所以可以通過自定義處理器來做擴展,如:

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)
十六、 信號
Django中提供了“信號調度”,用於在框架執行操作時解耦。通俗來講,就是一些動作發生的時候,信號允許特定的發送者去提醒一些接受者。
1、Django內置信號
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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內置的信號,僅需注冊指定信號,當程序執行相應操作時,自動觸發注冊函數:

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指上述導入的內容
2、自定義信號
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中,所以其會自動調用,而對於自定義信號則需要開發者在任意位置觸發。
更多:猛擊這里
十七、admin
django amdin是django提供的一個后台管理頁面,改管理頁面提供完善的html和css,使得你在通過Model創建完數據庫表之后,就可以對數據進行增刪改查,而使用django admin 則需要以下步驟:
- 創建后台管理員
- 配置url
- 注冊和配置django admin后台管理頁面
注:不建議新手經常使用admin,會形成依賴,核心的是model模塊的操作!
1、創建后台管理員
python manage.py createsuperuser
2、配置后台管理url(默認已配)
url(r'^admin/', include(admin.site.urls))
3、注冊和配置django admin 后台管理頁面
a、在admin中執行如下配置

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、設置數據表名稱

class UserType(models.Model): name = models.CharField(max_length=50) class Meta: verbose_name = '用戶類型' verbose_name_plural = '用戶類型'
c、打開表之后,設定默認顯示,需要在model中作如下配置

class UserType(models.Model): name = models.CharField(max_length=50) def __unicode__(self): # python3 is __str__(self) return self.name
d、為數據表添加搜索功能

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、添加快速過濾

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/
后續更新中……