Django請求生命周期
首先:對于所有的web架構來說本質就是一個socket服務端,浏覽器是socket用戶端
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5yN1YzM3AjM3cTMtEjMwYDN5QDMxUTMzAjNxAjMtEjMwEzM48CXzAjNxAjMvwVMyATMzgzLcd2bsJ2Lc12bj5ycn9Gbi52YuUTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.jpg)
路由系統
在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的請求進行管理都需要自定義中間件
中間件可以對進來的請求和出去的請求進行控制
中間件是一類。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5yN1YzM3AjM3cTMtEjMwYDN5QDMxUTMzAjNxAjMtEjMwEzM48CXzAjNxAjMvwVMyATMzgzLcd2bsJ2Lc12bj5ycn9Gbi52YuUTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.jpg)
看下面的代碼在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
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'[email protected]', '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
轉載于:https://www.cnblogs.com/luotianshuai/p/5278175.html