Django框架全面講解二

Django框架全面講解二

七、中間件(MiddleWare)

django 中的中間件(middleware),在django中,中間件其實就是一個類,在請求到來和結束後,django會根據自己的規則在合適的時機執行中間件中相應的方法。

在django項目的settings模塊中,有一個 MIDDLEWARE_CLASSES 變量,其中每一個元素就是一箇中間件,如下圖

img

中間件中可以定義五個方法,分別是:

  • 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

分析源碼得知前二個方法是從前往後執行的,後三個方法是從後往前執行的

img

所以前兩個方法是請求進來的,後三個方法是請求出去的

一張圖告訴你中間件的運行流程

img

自定義中間件

1、創建中間件類

class Middle_Test(object):
       
    def process_request(self,request):
        pass
    def process_view(self, request, callback, callback_args, callback_kwargs):
        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

1.使用 forms 模塊生成表單,主要處理GET請求
	1.forms模塊的作用
		通過forms模塊,允許將表單與class結合(表單與實體類結合),允許通過class生成表單
	2.使用forms模塊
		1.在應用中創建 forms.py 文件
		2.導入forms模塊
			from django import forms
		3.創建class,一個class對應生成一個表單
			class ClassName(forms.Form):
				pass
		4.創建屬性
			一個屬性對應到表單中生成一個控件
	3.在模板中解析 form 對象
		1.注意
			在模板中,需要:
				1.自定義 <form></form>
				2.自定義 提交按鈕
		2.處理方法
			1.在 views 中創建 form 的對象併發送到模板上
				form = RemarkForm()
				return render(request,'xxx.html',locals())
			2.在模板中進行解析
				1.手動解析
					{% for field in form %}
						{{field}} :
							表示的就是form對象中的一個獨立屬性
							表示的也就是一個獨立的控件
						{{field.label}}:
							表示的是控件中的label的值
					{% endfor %}
				2.自動解析
					1.{{form.as_p}}
						將form對象中的每個屬性使用p標記包裹起來再顯示
					2.{{form.as_ul}}
						將form對象中的每個屬性使用li標記包裹起來,再顯示
						注意:必須手動提供<ol><ul>
					3.{{form.as_table}}
						將form對象中的每個屬性用tr標記包裹起來,再顯示
						注意:必須手動提供<table>

2.通過 forms.Form 獲取表單數據 - POST
    1.通過 forms.Form 的構造函數來接收post數據
    	form = RemarkForm(request.POST)
    2.必須使form通過驗證後再獲取數據
    	form.is_valid()
    		返回True:提交的數據以及表單已通過所有的驗證,允許取值
    		返回False:未通過驗證,則不能正常取值
    3.獲取表單中的數據
    	通過 form.cleaned_data 來獲取提交的數據

form.py

from django import forms

#聲明ChoiceField要用到的數據
TOPIC_CHOICE = (
    ('1', '好評'),
    ('2', '中評'),
    ('3', '差評'),
)


class RemarkForm(forms.Form):
    #評論標題
    # forms.CharField() - 文本框
    # label : 控件前的文本標籤
    subject = forms.CharField(label='標題')
    #電子郵箱
    # forms.EmailField() - Email框
    # label : 控件前的文本標籤
    email = forms.EmailField(label='郵箱')
    #品論內容
    # widget=Textarea : 將當前的單行文本框變爲多行文本域
    message = forms.CharField(label='內容', widget=forms.Textarea)
    #品論級別
    # forms.ChoiceField() - 下拉列表框
    # choices : 表示當前下拉列表框中的數據,取值爲元組或列表
    topic = forms.ChoiceField(label='級別', choices=TOPIC_CHOICE)
    #是否保存-複選框
    isSaved = forms.BooleanField(label='是否保存')

views.py

def form_register(request):
    if request.method == 'GET':
        form = RegisterForm()
        return render(request,'07-form-register.html',locals())
    else:
        # 將request.POST中的數據提交給RegisterForm()
        form = RegisterForm(request.POST)
        # 將數據通過驗證
        if form.is_valid():
        # 驗證過後獲取數據並保存進數據庫
        	au = Author(**form.cleaned_data)
        	au.save()
        	return HttpResponse("Register OK")

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #id_subject{
        border:none;
        border-bottom:1px solid #000;
        outline:none;
        }
    </style>
</head>
<body>
      {% comment '手動解析' %}
    <form action="/06-form/" method="post">
      {% csrf_token %}
      {% for field in form %}
        <p>
          {{ field.label }}:{{ field }}
        </p>
      {% endfor %}
      <p>
        <input type="submit">
      </p>
    </form>
    {% endcomment %}

    {% comment '自動解析- {{ form.as_p }}' %}
    <form action="/06-form/" method="post">
      {{ form.as_p }}
      <p>
        <input type="submit">
      </p>
    </form>
    {% endcomment %}  
    
</body>
1.使用 forms 模塊
	2.forms模塊的高級處理
		將 Models 和 Forms 結合到一起使用
		1.在 forms.py 中創建 class ,繼承自 forms.ModelForm
		2.創建內部類Meta,去關聯 Model
			1.model : 指定要關聯的實體類
			2.fields : 指定從Model中取哪些字段生成控件
				1.取值 "__all__",表示全部屬性都要生成控件
				2.取值 列表,聲明允許生成控件的屬性名
			3.labels : 指定每個屬性所關聯的label,取值爲字典
				labels = {
					'屬性名':'label文本',
					'屬性名':'label文本',
				}
	3.內置小部件 - widget
		1.什麼是小部件
			小部件,表示的就是生成到網頁上的控件類型以及其他的html屬性
		2.常用小部件類型
			1.TextInput : type='text'
			2.PasswordInput : type='password'
			3.NumberInput : type='number'
			4.EmailInput : type='email'
			5.URLInput : type='url'
			6.HiddenInput : type='hidden'
			7.CheckboxInput : type='checkbox'
			8.Textarea : <textarea></textarea>
			9.Select : <select></select>
		3.小部件的使用
			1.繼承自 forms.Form 類
				1.基本版
					只指定控件的類型
					class RemarkForm(forms.Form):
						屬性 = forms.CharField(
							label='文本',
							widget=forms.小部件類型
						)
				2.高級版
					指定控件類型的基礎上還允許設置一些相關的HTML屬性到控件上
					屬性 = forms.CharField(
						label = '文本',
						widget = forms.小部件類型(
							attrs = {
								'html屬性名':'屬性值',
								'html屬性名':'屬性值',
							}
						)
					)
			2.繼承自 forms.ModelForm 類
				class XXXForm(forms.ModelForm):
					class Meta:
						model = xxxx
						fields = "__all__"[]
						labels = {
							'屬性1':'標籤1',
						}
						#指定小部件
						widgets = {
							"屬性1":forms.小部件類型(
								attrs = {
									'屬性':'值',
								}
							),
						}

form.py

class WidgetForm2(forms.ModelForm):
    class Meta:
        #指定關聯的實體
        model = Author
        #指定要顯示的字段
        fields = ['name','age','email']
        #指定字段對應的標籤
        labels = {
        'name':'用戶姓名',
        'age':'用戶年齡',
        'email':'用戶郵箱',
        }
        #指定字段對應的小部件
        widgets = {
        'age':forms.NumberInput(
            attrs = {
            'placeholder':'請輸入年齡',
            'class':'form-control',
            }
        ),
        'email':forms.EmailInput(
            attrs = {
            'placeholder':'請輸入您的電子郵箱',
            'class':'form-control',
            }
        )
    }

views.py

def widget2_views(request):
    if request.method == 'GET':
        form = WidgetForm2()
        return render(request,'08-widget1.html',locals())
    else:
		# 將request.POST中的數據提交給RegisterForm()
        form = RegisterForm(request.POST)
        # 將數據通過驗證
        if form.is_valid():
        # 驗證過後獲取數據並保存進數據庫
        	au = Author(**form.cleaned_data)
        	au.save()
        	return HttpResponse("Register OK")

html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
    input.form-control{
    border:1px solid #000;
    width:300px;
    height:30px;
    box-sizing:border-box;
    padding:3px 10px;
    outline:none;
    }
</style>
</head>
<body>
    <form action="/09-widget2">
        {{ form.as_p }}
    </form>
</body>
</html>

九、 認證系統(auth)

auth模塊是Django提供的標準權限管理系統,可以提供用戶身份認證, 用戶組管理,並且可以和admin模塊配合使用.

在INSTALLED_APPS中添加’django.contrib.auth’使用該APP, auth模塊默認啓用.

新建用戶

from django.contrib.auth.models import User

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_protec

應用

1、普通表單

# veiw中設置返回值:
return render(request, 'xxx.html', data)
   
# html中設置Token:
{% csrf_token %}

十一、2.cookies 和 session

2.cookies 和 session
	1.cookies
		1.django 中使用 cookies
			1.設置cookies的值(將數據保存到客戶端)
				語法:
					響應對象.set_cookie(key,value,expires)
					key:cookie的名字
					value:cookie的值
					expires:保存時間,以s爲單位
				1.不使用模板
					resp = HttpResponse('響應給客戶端的一句話')
					resp.set_cookie(key,value,expires)
					return resp
				2.使用模板
					resp = render(request,'xxx.html',locals())
					resp.set_cookie(key,value,expires)
					return resp
				3.使用重定向
					resp = redirect('/地址/')
					resp.set_cookie(key,value,expires)
					return resp
			2.獲取cookies的值
				伴隨着請求對象到達服務器之後再獲取cookie的值
				request.COOKIES:封裝了當前訪問站點下的所有的cookie的信息
			3.刪除cookie的值
				通過響應對象通知客戶端刪除數據
				resp.delete_cookie(key)
			
	2.session
		1.設置 session 的值
			request.session['key'] =2.獲取 session 的值
			value = request.session['key']
			value = request.session.get('key')
		3.刪除 session 的值
			del request.session['key']
		4.有關 session 的配置
			在 settings.py 中,有關session的設置
			1.SESSION_COOKIE_AGE
				作用:設置sessionID在cookies中的存活時間
				ex:
					SESSION_COOKIE_AGE=60*30
			2.SESSION_EXPIRE_AT_BROWSER_CLOSE
				作用:設置瀏覽器關閉時則清除服務器上對應的session空間

				ex:
					SESSION_EXPIRE_AT_BROWSER_CLOSE = True

十二、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是動態網站,所有每次請求均會去數據進行相應的操作,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個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做單獨的緩存

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章