天天看點

Python之路【第十六篇續】Django進階篇

Django請求生命周期

首先:對于所有的web架構來說本質就是一個socket服務端,浏覽器是socket用戶端

Python之路【第十六篇續】Django進階篇

路由系統

在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傳參

咱們看下園的分頁連接配接如下圖:

Python之路【第十六篇續】Django進階篇

問:如果有這麼多的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,那麼我們的路由規則隻能寫在一個檔案裡嗎?

Python之路【第十六篇續】Django進階篇

當然不是,我們可以通過下面的方式來把他分開:

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的請求進行管理都需要自定義中間件

  中間件可以對進來的請求和出去的請求進行控制

  中間件是一類。

Python之路【第十六篇續】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',
]      

當有請求過來的時候,預設從上倒下執行!然後在傳回的時候從下面在傳回回去,如下圖:

Python之路【第十六篇續】Django進階篇

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、自定義中間件

Python之路【第十六篇續】Django進階篇

\

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有傳回值得話他的請求流程是這樣的:

Python之路【第十六篇續】Django進階篇

但是如果在process_request或者process_view又傳回值得話那麼流程就完全不一樣了!

舉例:如果有m1和m2兩個中間件,如果我在m1中的request方法中設定了,如果通路為1.1.1.1那麼傳回要一個404,那麼他的通路流程是這樣的:

Python之路【第十六篇續】Django進階篇

process_exception  什麼時候觸發呢?咱們定義的views.index出錯的時候他就會捕捉到然後執行咱們定義的process_exception方法如下圖:

Python之路【第十六篇續】Django進階篇

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!

Python之路【第十六篇續】Django進階篇

當用戶端通路過來後,server端會在IE裡生成一個Cookie,當通路過來的時候就可以通過Cookie進行判斷

2、結構

1、自動生成一段字元串

2、将字元串發送到用戶端的浏覽器,同時把字元串當做key放在session裡。(可以了解為session就是一個字典)

3、在使用者的session對應的value裡設定任意值

Python之路【第十六篇續】Django進階篇
Python之路【第十六篇續】Django進階篇

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顯示:

Python之路【第十六篇續】Django進階篇

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格式的時候!

Python之路【第十六篇續】Django進階篇

這樣在後端我們是不是就有一套驗證的機制?就可以通過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>      

現在在去點選下看下效果:

Python之路【第十六篇續】Django進階篇

這樣如果,我都按照要求送出,就可以取到資料了?這樣咱們就不用自己去拿資料是,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'手機不能為空'})      

效果:

Python之路【第十六篇續】Django進階篇

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,标簽
                              )      

看下效果:

Python之路【第十六篇續】Django進階篇

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'備注'})

     )      

效果:

如果為空的話會提示,不能為空如果格式不對的話會提示:

Python之路【第十六篇續】Django進階篇

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中如果不進行處理預設顯示的是:

Python之路【第十六篇續】Django進階篇

看下他的實際是什麼内容:

{'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'])]}      

是以我們自定義一個模闆語言對其進行修飾:

Python之路【第十六篇續】Django進階篇

然後在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>      

顯示效果如下:

Python之路【第十六篇續】Django進階篇

因為模闆語言不支援用索引的方式取值,是以我們通過自定義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