Django請求生命周期
首先:對於所有的web框架來說本質就是一個socket服務端,瀏覽器是socket客戶端
路由系統
在Django的urls中我們可以根據一個URL對應一個函數名來定義路由規則如下:
from cmdb import views urlpatterns = [ url(r'^login/$', views.login), url(r'^index/$', views.index), url(r'^lists/$', views.lists), url(r'^add/$', views.add), ]
2、默認URL
上面一個URL對應一個函數!我們可以在整個的url最下面里設置一個默認的URL,當用戶訪問我們的網站的時候沒有指定詳細的URL的時候我們默認讓他們跳轉到一個URL。
urlpatterns = [ url(r'^login/$', views.login), url(r'^index/$', views.index), url(r'^lists/$', views.lists), url(r'^add/$', views.add), url(r'^$', views.login), ]
這里需要注意下:當客戶訪問過來請求的時候,到達路由系統后是根據正則來匹配的,如果上面的匹配成功了,后面的路由規則將不會繼續匹配,需要注意!!!!所以我們在后面都加一個$來做結尾
3、動態URL
3.1、動態URL傳參
咱們看下園的分頁連接如下圖:
問:如果有這么多的RUL難道我們都要給他寫一個路由規則嗎?當然不是,會累死的,那他是怎么實現的呢?在上面的默認的URL中我們就說過他的路由功能是支持“正則表達式”的!
所以我們可以這么寫:
url(r'^user_list/(\d+)$', views.user_list),
views.user_list
def user_list(request,chose_id): return HttpResponse(chose_id)
這里當用戶點擊的時候login后的數字,會自動的傳給views.user_list作為參數,因為這個是Django調用的,不是咱們調用的。
他這里會做兩步操作:
1、獲取user_list后面的這個值
2、運行views.user_list這個函數,並把獲取的值自動傳給views.user_list作為參數他的參數
3.2、動態URL傳多個參數
問:我是否可以傳多個參數?
可以傳多個參數它是已/來分割的。
url(r'^user_list/(\d+)/(\d+)$', views.user_list),
views.user_list
def user_list(request,chose_id,chose_id2): return HttpResponse(chose_id+chose_id2)
輸入:http://127.0.0.1:8000/user_list/8/10 效果就是:810
他的順序是:正序的,你先給他傳那個值,第一個參數就是那個
3.3、動態URL傳參數以Key:value的形式
通過正則表達式的分組來做!
url(r'^user_list/(?P<v1>\d+)/(?P<V2>\d+)$', views.user_list),
這里?p<v1>這里的v1就是key,vlaue就是傳進去的值,
def user_list(request,v2,v1): print v2 , v1 return HttpResponse(v1+v2)
這樣我們就不必按照順序去取了,可以通過key,value的方式來取傳進來的值
4、URL中專(分級匹配)
在實際的生產環境中有這么一種情況:在一個project下面有很多APP,那么我們的路由規則只能寫在一個文件里嗎?
當然不是,我們可以通過下面的方式來把他分開:
url(r'^app01/', include("app01.urls")),
然后在app01內創建一個文件urls,不要忘記注冊app。然后在訪問app01里的url的時候通過:hostip:port/app01/index or hostip:port/app01/login
5、基於反射實現動態路由設計
有很多的WEB框架,他和Django不太一樣。比如mvc他會將所有的URL做成一個分類的形式。在Django中咱們一般是一個url對應一個函數。
但是在其他的WEB框架中他們也把url也進行用正則處理了。比如下面:
url(r'^(?P<controller>\w+)/(?P<action>\w+)', mp), #咱們給他做個定義mp中第一個是文件比如 #home.py 第二個參數是文件中的函數 def index # #/home/index/ #/login/index/ #/update/index/
但是上面的方法僅僅是通過反射來實現的,通過文件找到里面的函數然后執行!
但是在Django中不建議使用此方法。因為不同的WEB框架建議你使用不同的方式,Django就不建議使用反射
中間件
中間件定義:
中間件是一個、一個的管道,如果相對任何所有的通過Django的請求進行管理都需要自定義中間件
中間件可以對進來的請求和出去的請求進行控制
中間件是一類。
看下面的代碼在settings里中間件的類:
MIDDLEWARE_CLASSES = [ 'django.middleware.security.SecurityMiddleware', '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', ]
當有請求過來的時候,默認從上倒下執行!然后在返回的時候從下面在返回回去,如下圖:
2、自定義中間件
中間件中可以定義四個方法,分別是:
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_exception(self, request, exception)
- process_response(self, request, response)
process_exception 這個方法只有在出現錯誤的時候才會觸發
先寫一個自定義中間件,然后在看他的原理和源碼:
2.1、自定義中間件
\
class Testmiddle(object): def process_request(self,request): print 'Testmiddle process_request' def process_view(self, request, callback, callback_args, callback_kwargs): print 'Testmiddle process_view' def process_exception(self, request, exception): pass def process_response(self, request, response): print 'Testmiddle process_response' return response class Nextmiddle(object): def process_request(self,request): print 'Nextmiddle process_request' def process_view(self, request, callback, callback_args, callback_kwargs): print 'Nextmiddle process_view' def process_exception(self, request, exception): pass def process_response(self, request, response): print 'Nextmiddle process_response' return response
2.2、注冊中間件
MIDDLEWARE_CLASSES = [ 'django.middleware.security.SecurityMiddleware', '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', 'middleware.middle.Testmiddle', 'middleware.middle.Nextmiddle', ]
2.3、測試使用url和views
from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/$', views.index), ]
def index(request): print 'This app01 Views.index' return HttpResponse('OK')
2.4、查看輸出結果:
''' Testmiddle process_request Nextmiddle process_request Testmiddle process_view Nextmiddle process_view This app01 Views.index Nextmiddle process_response Testmiddle process_response '''
從輸出結果可以看出:
他是先執行Testmiddle 的request 方法又執行了Nextmiddle的 process_request方法。。。。
2.5、原理:
當請求進來了到達中間件
去settings里面找到MIDDLEWARE_CLASSES,MIDDLEWARE_CLASSES是一個元組
有4個列表:
process_request_lsit = [] process_view_list = [] process_response_list = [] 然后他循環MIDDLEWARE_CLASSES這個類: for 類 in MIDDLEWARE_CLASSES: obj = 類() if obj里有process_request方法: process_request_lsit.append(obj.process_request)
然后循環后后執行:
for i in process_request_list: i() #加括號執行方法 for i in process_view_list: i() ............
源碼:

def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE_CLASSES. Must be called after the environment is fixed (see __call__ in subclasses). """ self._view_middleware = [] self._template_response_middleware = [] self._response_middleware = [] self._exception_middleware = [] request_middleware = [] for middleware_path in settings.MIDDLEWARE_CLASSES: mw_class = import_string(middleware_path) try: mw_instance = mw_class() except MiddlewareNotUsed as exc: if settings.DEBUG: if six.text_type(exc): logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc) else: logger.debug('MiddlewareNotUsed: %r', middleware_path) continue if hasattr(mw_instance, 'process_request'): request_middleware.append(mw_instance.process_request) if hasattr(mw_instance, 'process_view'): self._view_middleware.append(mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): self._template_response_middleware.insert(0, mw_instance.process_template_response) if hasattr(mw_instance, 'process_response'): self._response_middleware.insert(0, mw_instance.process_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.insert(0, mw_instance.process_exception) # We only assign to this when initialization is complete as it is used # as a flag for initialization being complete. self._request_middleware = request_middleware
3、中間件的流程梳理
首先看下自定義的中間件中的process_response方法他是有返回值的其他的是沒有返回值的。這個return response是什么呢?
這個response就是咱們自定義的views.index返回的結果!
def process_response(self, request, response): print 'Testmiddle process_response' return response
如果在其他的沒有返回值得,僅有process_response有返回值得話他的請求流程是這樣的:
但是如果在process_request或者process_view又返回值得話那么流程就完全不一樣了!
舉例:如果有m1和m2兩個中間件,如果我在m1中的request方法中設置了,如果訪問為1.1.1.1那么返回要一個404,那么他的訪問流程是這樣的:
process_exception 什么時候觸發呢?咱們定義的views.index出錯的時候他就會捕捉到然后執行咱們定義的process_exception方法如下圖:
Django緩存
由於Django是動態網站,所有每次請求均會去數據進行相應的操作,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個views的返回值保存至內存或者Redis中,5分鍾內再有人來訪問時,則不再去執行view中的操作,而是直接從內存或者Redis中之前緩存的內容拿到,並返回。
舉個例子來說:如果訪問量比較大的時候,有很多相同的操作比如:有時候請求的數據比如訪問同一條數據,或者同一個頁面的時候,其實是沒必要的。
Django支持,mysql,Redis、Memecache、文件的方式做緩存,並且可以設置超時時間。
settings配置:
CACHES = { 'default': { #定義已文件的方式進行cache 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', #cache文件的存放路徑 'LOCATION': os.path.join(BASE_DIR, 'cache'), #超時時間為600妙 'TIMEOUT': 600, 'OPTIONS': { 'MAX_ENTRIES': 1000 } } }
給請求應用,就是使用裝飾器
from django.views.decorators.cache import cache_page #這里設置的是 60秒 * 15 ,15分鍾之后 @cache_page(60 * 15) def cache_page(request): current = str(time.time()) return HttpResponse(current)
Session&Cookie
Cookie就是一段字符串,保存於本機電腦上。
session 保存於服務器,用來保存用戶的會話信息,依賴於Cookies
1、流程
舉個例子,咱們在登錄一個網站后,拿JD舉例,如果我登錄進去之后,在想點擊訂單的時候。server斷怎么判斷我是“我”,而不是其他人呢?
Http是短連接,那么Server端肯定有一個保存我登錄狀態的地方(session),那server怎么判斷是我發送過來的請求呢?就是通過Cookie!
當客戶端訪問過來后,server端會在IE里生成一個Cookie,當訪問過來的時候就可以通過Cookie進行判斷
2、結構
1、自動生成一段字符串
2、將字符串發送到客戶端的瀏覽器,同時把字符串當做key放在session里。(可以理解為session就是一個字典)
3、在用戶的session對應的value里設置任意值
3、操作
3.1、操作session
- 獲取session:request.session[key]
- 設置session:reqeust.session[key] = value
- 刪除session:del request[key]
request.session.set_expiry(value) * 如果value是個整數,session會在些秒數后失效。 * 如果value是個datatime或timedelta,session就會在這個時間后失效。 * 如果value是0,用戶關閉瀏覽器session就會失效。 * 如果value是None,session會依賴全局session失效策略。
實例:
def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'shuai' and password == '123': result = request.session.get('IS_LOGIN', None) print result request.session['IS_LOGIN'] = True return redirect('/index/') obj = forms.LoginForm() # 如果登錄成功,寫入session,跳轉index return render(request, 'account/login.html', {'model': obj}) def index(request): ''' 如果用戶已經登錄 ''' is_login = request.session.get('IS_LOGIN',False) if is_login: return render(request, 'home/index.html') else: return redirect('/login/')
注:這里需要注意在session中,我們可以設置多個key:value的值,方便我們做很多事情,比如判斷哪個用戶:
如果用戶登錄后,那么他肯定有一個cookie那么他在訪問購物車的時候,怎么判斷是哪個用戶呢?我們可以在session設置,當用戶登錄的時候,我們把的用戶名,增加到session中,那么用戶攜帶cookie訪問的時候,我們就能判斷是哪個一用來訪問的!
比如下面的對應關系:
user1
cookie :aaaa
server session(舉例格式)
{session:aaaa{'IS_LOGIN':'True',username:'shuaige'}}
4、Session和Cookie好處
使用Session和Cookie的好處:Cookie可以理解為一個身份證ID,你只能拿着他去和Server端進行通信,如果你沒有這個ID那么server端也不知道你是誰!
實例:(0 0 !)
我在寫博客的時候在做Cookie和Session的實驗,把Cookie刪掉了!當我保存的時候直接給我提出來了,為什么呢?就是因為,server端不知道我是誰了,我已經沒有密鑰了。
所以,只要Session和Cookie任意一方失效,就可以理解為:
Cookie失效就相當於身份證ID過期,需要重新認證才可以繼續使用。Session失效就相當於銀行里的數據標識此ID無效,也需要重新申請。
Django Form表單
在實際的生產環境中比如登錄和驗證的時候,我們一般都使用Jquery+ajax來判斷用戶的輸入是否為空,假如JS被禁用的話,咱們這個認證屏障是不是就消失了呢?(雖然一般不會禁用掉但是還是存在風險)
所以我們一般做兩種認證一種是前端做一遍認證,在后端做一遍認證
首先咱們看一下下面的案例:
#/usr/bin/env python #-*- coding:utf-8 -*- from django.shortcuts import render # Create your views here. def user_list(request): host = request.POST.get('host') port = request.POST.get('port') mail = request.POST.get('mail') mobile = request.POST.get('mobile') #這里有個問題,如果,這個from表單有20個input,你在這里是不是的取20次? #驗證: #輸入不能為空,並且有的可以為空有的不可以為空 #如果email = 11123123 這樣合法嗎? #如果mobile = 11123123 這樣合法嗎? #如果ip = 11123123 這樣合法嗎? ''' 你在這里是不是需要做一大堆的輸入驗證啊?並且有很多這種頁面會存在這種情況,如果每個函數都這樣做估計就累死了 ''' return render(request,'user_list.html')
在樣能解決這個問題呢?通過Django的form來實現,其他語言也有叫做(模型綁定)
Django的form的作用:
1、生成html標簽
2、用來做用戶提交的驗證
1、生成html標簽
views
from django import forms class UserInfo(forms.Form): email = forms.EmailField(required=False) #required是否可以為空,如果為False說明可以為空 host = forms.CharField() #如果required不寫默認為Ture port = forms.CharField() mobile = forms.CharField() def user_list(request): obj = UserInfo() #創建了這個對象 return render(request,'user_list.html',{'obj':obj})#然后把對象傳給html
html調用
<form action="/user_list/" method="post"> <p>主機:{{ obj.host }}</p> <p>端口:{{ obj.port }}</p> <p>郵箱:{{ obj.email }}</p> <p>手機:{{ obj.mobile }}</p> <input type="submit" value="submit"/> </form>
把我們的對象穿進去,html在引用的時候直接obj.host就可以自動生成html標簽,然后看下html顯示:
2、簡單的form表單驗證用戶輸入的內容
def user_list(request): obj = UserInfo() #創建了這個對象 if request.method == 'POST': #獲取用戶輸入一句話就搞定 user_input_obj = UserInfo(request.POST) ''' 咱們把post過來的數據當參數傳給UserInfo咱們定義的這個類,UserInfo會自動會去你提交的數據 email/host/port/mobile 自動的封裝到user_input_obj里,封裝到這個對象里我們就可以判斷輸入是否合法 ''' print user_input_obj.is_valid() # return render(request,'user_list.html',{'obj':obj})#然后把對象傳給html
當我們輸入不合法的時候,(在創建類設置的需求)為空、或者不是email格式的時候!
這樣在后端我們是不是就有一套驗證的機制?就可以通過is_valid()來判斷用戶輸入是否合法!如果不合法就把返回信息發送過去,如果合法獲取數據操作即可!
捕獲錯誤信息並返回
from django import forms class UserInfo(forms.Form): email = forms.EmailField(required=True) #required是否可以為空,如果為False說明可以為空 host = forms.CharField() #如果required不寫默認為Ture port = forms.CharField() mobile = forms.CharField() def user_list(request): obj = UserInfo() #創建了這個對象 if request.method == 'POST': #獲取用戶輸入一句話就搞定 user_input_obj = UserInfo(request.POST) ''' 咱們把post過來的數據當參數傳給UserInfo咱們定義的這個類,UserInfo會自動會去你提交的數據 email/host/port/mobile 自動的封裝到user_input_obj里,封裝到這個對象里我們就可以判斷輸入是否合法 ''' if user_input_obj.is_valid(): #判斷用戶輸入是否合法 data = user_input_obj.clean() #獲取用戶輸入 print data else: #如果發生錯誤,捕捉錯誤 error_msg = user_input_obj.errors print error_msg #打印一下然后看下他的類型 ''' <ul class="errorlist"> <li>mobile<ul class="errorlist"><li>This field is required. </li></ul></li> <li>host<ul class="errorlist"><li>This field is required.</li></ul></li> <li>port<ul class="errorlist"><li>This field is required.</li></ul></li> </ul> ''' #然后把錯誤信息返回 return render(request,'user_list.html',{'obj':obj,'errors':error_msg,})#然后把對象傳給html,在把錯誤信息傳遞過去 return render(request,'user_list.html',{'obj':obj,})#然后把對象傳給html
html標簽,使用error輸出
<form action="/user_list/" method="post"> <p>主機:{{ obj.host }}<span>{{ errors.host }}</span></p> <p>端口:{{ obj.port }}<span>{{ errors.port }}</span></p> <p>郵箱:{{ obj.email }}<span>{{ errors.email }}</span></p> <p>手機:{{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <input type="submit" value="submit"/> </form>
現在在去點擊下看下效果:
這樣如果,我都按照要求提交,就可以取到數據了?這樣咱們就不用自己去拿數據是,NICE,NICE~~
{'mobile': u'123456789', 'host': u'1.1.1.1', 'email': u'shuaige@qq.com', 'port': u'8000'}
3、form表單定制化
3.1、自定義報錯內容
在form里有一個參數:error_messages 在他這里就可以定義報錯內容
class UserInfo(forms.Form): email = forms.EmailField(required=True,error_messages={'required':u'郵箱不能為空'}) #required是否可以為空,如果為False說明可以為空 host = forms.CharField(error_messages={'required':u'主機不能為空'}) #如果required不寫默認為Ture port = forms.CharField(error_messages={'required':u'端口不能為空'}) mobile = forms.CharField(error_messages={'required':u'手機不能為空'})
效果:
3.2、我想給form表單添加一個屬性
class UserInfo(forms.Form): email = forms.EmailField(required=True,error_messages={'required':u'郵箱不能為空'}) #required是否可以為空,如果為False說明可以為空 host = forms.CharField(error_messages={'required':u'主機不能為空'}) #如果required不寫默認為Ture port = forms.CharField(error_messages={'required':u'端口不能為空'}) mobile = forms.CharField(error_messages={'required':u'手機不能為空'}, widget=forms.TextInput(attrs={'class':'form-control','placeholder':u'手機號碼'}) #這里默認是TextInput,標簽 )
看下效果:
3.3、在給他增加一個備注
class UserInfo(forms.Form): email = forms.EmailField(required=True,error_messages={'required':u'郵箱不能為空'}) #required是否可以為空,如果為False說明可以為空 host = forms.CharField(error_messages={'required':u'主機不能為空'}) #如果required不寫默認為Ture port = forms.CharField(error_messages={'required':u'端口不能為空'}) mobile = forms.CharField(error_messages={'required':u'手機不能為空'}, widget=forms.TextInput(attrs={'class':'form-control','placeholder':u'手機號碼'}) #這里默認是TextInput,標簽 ) #咱們在新增一個備注 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'form-control','placeholder':u'備注'}) )
html代碼
<form action="/user_list/" method="post"> <p>主機:{{ obj.host }}<span>{{ errors.host }}</span></p> <p>端口:{{ obj.port }}<span>{{ errors.port }}</span></p> <p>郵箱:{{ obj.email }}<span>{{ errors.email }}</span></p> <p>手機:{{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>備注:{{ obj.memo }}<span>{{ errors.memo }}</span></p> <input type="submit" value="submit"/> </form>
4、自定義正則表達式增加判斷規則
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 UserInfo(forms.Form): email = forms.EmailField(required=True,error_messages={'required':u'郵箱不能為空'}) #required是否可以為空,如果為False說明可以為空 host = forms.CharField(error_messages={'required':u'主機不能為空'}) #如果required不寫默認為Ture port = forms.CharField(error_messages={'required':u'端口不能為空'}) #默認mobile里有一個默認為空的機制,我們在原有的參數里增加怎們自定義的方法 mobile = forms.CharField(validators=[mobile_validate,],#應用咱們自己定義的規則 error_messages={'required':u'手機不能為空'}, widget=forms.TextInput(attrs={'class':'form-control','placeholder':u'手機號碼'}) #這里默認是TextInput,標簽 ) #咱們在新增一個備注 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'form-control','placeholder':u'備注'}) )
效果:
如果為空的話會提示,不能為空如果格式不對的話會提示:
5、生成select標簽
class UserInfo(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'})) 。。。。。。。。。
html內
<form action="/user_list/" method="post"> <p>用戶類型:{{ obj.user_type }}<span>{{ errors.user_type }}</span></p> <p>主機:{{ obj.host }}<span>{{ errors.host }}</span></p> <p>端口:{{ obj.port }}<span>{{ errors.port }}</span></p> <p>郵箱:{{ obj.email }}<span>{{ errors.email }}</span></p> <p>手機:{{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>備注:{{ obj.memo }}<span>{{ errors.memo }}</span></p> <input type="submit" value="submit"/> </form>
6、關於后端驗證
這個后端驗證是必須要有驗證機制的,前端可以不寫但是后端必須要寫!前端的JS是可以被禁用掉到。
6、Django form漂亮的顯示錯誤信息
設置顯示error的樣式
error_msg = user_input_obj.errors.as_data()#這里原來什么都沒寫,默認是ul的樣式,默認是as_ul(),如果我們寫成as_data()返回的就是一個原生的字符串 #還有一個as_json
實例:
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 UserInfo(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'})) email = forms.EmailField(required=True,error_messages={'required':u'郵箱不能為空'}) #required是否可以為空,如果為False說明可以為空 host = forms.CharField(error_messages={'required':u'主機不能為空'}) #如果required不寫默認為Ture port = forms.CharField(error_messages={'required':u'端口不能為空'}) #默認mobile里有一個默認為空的機制,我們在原有的參數里增加怎們自定義的方法 mobile = forms.CharField(validators=[mobile_validate,],#應用咱們自己定義的規則 error_messages={'required':u'手機不能為空'}, widget=forms.TextInput(attrs={'class':'form-control','placeholder':u'手機號碼'}) #這里默認是TextInput,標簽 ) #咱們在新增一個備注 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'form-control','placeholder':u'備注'})) def user_list(request): obj = UserInfo() #創建了這個對象 if request.method == 'POST': #獲取用戶輸入一句話就搞定 user_input_obj = UserInfo(request.POST) if user_input_obj.is_valid(): #判斷用戶輸入是否合法 data = user_input_obj.clean() #獲取用戶輸入 print data else: #如果發生錯誤,捕捉錯誤 error_msg = user_input_obj.errors.as_data()#這里原來什么都沒寫,默認是ul的樣式,默認是as_ul(),如果我們寫成as_data()返回的就是一個原生的字符串 #還有一個as_json print error_msg #打印一下然后看下他的類型 #然后把錯誤信息返回 return render(request,'user_list.html',{'obj':obj,'errors':error_msg,})#然后把對象傳給html,在把錯誤信息傳遞過去 return render(request,'user_list.html',{'obj':obj,})#然后把對象傳給html
這里在html中如果不進行處理默認顯示的是:
看下他的實際是什么內容:
{'mobile': [ValidationError([u'\u624b\u673a\u4e0d\u80fd\u4e3a\u7a7a'])], 'host': [ValidationError([u'\u4e3b\u673a\u4e0d\u80fd\u4e3a\u7a7a'])], 'email': [ValidationError([u'\u90ae\u7bb1\u4e0d\u80fd\u4e3a\u7a7a'])], 'port': [ValidationError([u'\u7aef\u53e3\u4e0d\u80fd\u4e3a\u7a7a'])]}
所以我們自定義一個模板語言對其進行修飾:
然后在html中調用
{% load cmdb_tag %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Shuai</title> </head> <body> <form action="/user_list/" method="post"> <p>用戶類型:{{ obj.user_type }}<span>{% error_message errors.user_type %}</span></p> <p>主機:{{ obj.host }}<span>{% error_message errors.host %}</span></p> <p>端口:{{ obj.port }}<span>{% error_message errors.port %}</span></p> <p>郵箱:{{ obj.email }}<span>{% error_message errors.email %}</span></p> <p>手機:{{ obj.mobile }}<span>{% error_message errors.mobile %}</span></p> <p>備注:{{ obj.memo }}<span>{% error_message errors.memo %}</span></p> <input type="submit" value="submit"/> </form> </body> </html>
顯示效果如下:
因為模板語言不支持用索引的方式取值,所以我們通過自定義simp_tag來進行取值
Ajax
1、單條數據提交
在上面的原有例子中的html中新增下面html內容
<form action="/user_list/" method="post"> <input type="button" onclick="Ajaxsubmit();" value="提交"/> <table> <thead> <tr> <th>主機名</th> <th>端口</th> </tr> </thead> <tbody> <tr> <td>1.1.1.1</td> <td>80000</td> </tr> <tr> <td>1.1.1.1</td> <td>80000</td> </tr> </tbody> </table> </form> <script type="text/javascript" src="/static/jquery-2.2.1.min.js"></script> <script> function Ajaxsubmit(){ var host = '1.1.1.1'; var port = '8000'; $.ajax({ url:"/ajax_data/", type:'POST', data:{h:host,p:port}, success:function(arg){ } }) } </script>
注釋:
$.ajax({ url:"/ajax_data/", #目標URL type:'POST', #請求方式 data:{h:host,p:port}, 以h和p為key用戶的輸入為value:<QueryDict: {u'h': [u'1.1.1.1'], u'p': [u'8000']}> success:function(arg){ }
增加URL和views
url(r'^ajax_data/', views.ajax_data),
def ajax_data(request): print request.POST return HttpResponse('OK')
2、ajax多條數據提交
在原來的基礎上修改Jquery
<script> function Ajaxsubmit(){ var array_users = [ {'username':'shuaige','arg':18}, {'username':'tianshuai','arg':18}, {'username':'shuai','arg':18}, ]; $.ajax({ url:"/ajax_mdata/", type:'POST', data:{data:array_users}, success:function(arg){ } }) } </script>
添加urls&views
url(r'^ajax_mdata/$', views.ajax_mdata),
views
def ajax_mdata(request): print request.POST return HttpResponse('OK')
點擊提交看下(在server端打印看下):
<QueryDict: {u'data[1][username]': [u'tianshuai'], u'data[0][username]': [u'shuaige'], u'data[0][arg]': [u'18'], u'data[1][arg]': [u'18'], u'data[2][username]': [u'shuai'], u'data[2][arg]': [u'18']}>
上面的結果數據是有問題的!他給咱們做了個加工,咱們沒給他傳data[1],data[0]了嗎?
所以咱們的在ajax增加參數
<script> function Ajaxsubmit(){ var array_users = [ {'username':'shuaige','arg':18}, {'username':'tianshuai','arg':18}, {'username':'shuai','arg':18}, ]; $.ajax({ url:"/ajax_mdata/", type:'POST', tradition: true, data:{data:JSON.stringify(array_users)}, success:function(arg){ } }) } </script>
增加了兩項:
#以原生的模式傳過去 tradition: true, #把數組做一步處理轉成字符串 data:{data:JSON.stringify(array_users)},
3、在一個Ajax請求之后,返回信息應該更職業化,不能單單發送一個字符串
看下面的就不像程序員:
def ajax_data(request): print request.POST return HttpResponse('OK')
應該這么寫:(下面的例子先用json來做,不過還有一個json response)
import json def ajax_data(request): ret = {'status':True,'error':''} try: print request.POST except Exception,e: ret['status'] = False ret['error'] = str(e) #在上面如果他出錯我就把他ret[status] = False return HttpResponse(json.dumps(ret))
html的js也得修改下:
<script> function Ajaxsubmit(){ var array_users = [ {'username':'shuaige','arg':18}, {'username':'tianshuai','arg':18}, {'username':'shuai','arg':18}, ]; $.ajax({ url:"/ajax_mdata/", type:'POST', tradition: true, data:{data:JSON.stringify(array_users)}, success:function(arg){ var callback_dict = $.parseJSON(arg);//這里把字符串轉換為對象 //然后咱們就可以判斷 if(callback_dict){//執行成功了 //簡單測試 alert('提交成功') }else{//如果為False執行失敗了 alert(callback_dict.error) } } }) } </script>
參考鏈接:本人騷師:http://www.cnblogs.com/wupeiqi/articles/5237704.html