Django - 請求與響應、表單、中間件、上下文處理器

請求與響應篇html

 

1、HttpRequest對象python

服務器接收到http協議的請求後,會根據報文建立HttpRequest對象。視圖函數的第一個參數(request)是HttpRequest對象在django.http模塊中定義了HttpRequest對象的APIajax

所謂的API,在django中就是屬性、方法。chrome

(一).HttpRequest對象的屬性及方法django

屬性:
path:一個字符串,表示請求的頁面的完整路徑,不包含域名
method:一個字符串,表示請求使用的HTTP方法,經常使用值包括:'GET''POST'
encoding:一個字符串,表示提交的數據的編碼方式
若是爲None則表示使用瀏覽器的默認設置,通常爲utf-8
這個屬性是可寫的,能夠經過修改它來修改訪問表單數據使用的編碼,接下來對屬性的任何訪問將使用新的encoding值
GET:一個相似於字典的對象,包含get請求方式的全部參數
POST:一個相似於字典的對象,包含post請求方式的全部參數
FILES:一個相似於字典的對象,包含全部的上傳文件
COOKIES:一個標準的Python字典,包含全部的cookie,鍵和值都爲字符串
session:一個既可讀又可寫的相似於字典的對象,表示當前的會話,只有當Django 啓用會話的支持時纔可用,詳細內容見「狀態保持」

方法:
is_ajax():若是請求是經過XMLHttpRequest發起的,則返回True
View Code

(二).QueryDict對象json

request對象的GET、POST屬性,都是QueryDict類型的對象。它不是python的字典!QueryDict類型的對象用來處理同一個鍵帶有多個值的狀況。瀏覽器

(1).get()緩存

根據鍵獲取值,只能獲取鍵的一個值。若是一個鍵同時擁有多個值,獲取最後一個值安全

(2).getlist()服務器

根據鍵獲取值,將鍵的值以列表返回,能夠獲取一個鍵的多個值。

(3).例

dict.get('',default)  # 或簡寫爲 dict['鍵']
dict.getlist('',default)
View Code

(三).GET屬性

(1).QueryDict類型的對象

(2).包含get請求方式的全部參數

(3).與url請求地址中的參數對應,在url的?後面進行拼接

(4).參數的格式是鍵值對,如key1=value1

(5).多個參數之間,使用&鏈接,如key1=value1&key2=value2

(四).POST屬性

(1).QueryDict類型的對象

(2).包含post請求方式的全部參數

(3).與form表單中的控件對應

(4).表單中控件要有name屬性,則name屬性的值爲鍵,value屬性的值爲鍵,構成鍵值對提交

(5).對於checkbox控件,name屬性同樣爲一組,當控件被選中後會被提交,存在一鍵多值的狀況

 

2、HttpResponse對象

(一).屬性及方法

屬性:
content:表示返回的內容,字符串類型
charset:表示response採用的編碼字符集,字符串類型
status_code:響應的HTTP響應狀態碼

方法:
init:使用頁內容實例化HttpResponse對象
write(content):以文件的方式寫
flush():以文件的方式輸出緩存區
set_cookie(key, value='', max_age=None, expires=None):設置Cookie
key、value都是字符串類型
max_age是一個整數,表示在指定秒數後過時
expires是一個datetime或timedelta對象,會話將在這個指定的日期/時間過時,注意datetime和timedelta值只有在使用PickleSerializer時纔可序列化
max_age與expires二選一
若是不指定過時時間,則關閉瀏覽器就失效.
delete_cookie(key):刪除指定的key的Cookie,若是key不存在則什麼也不發生
View Code

(二).cookie的例子

def cookie_test(request):
    response = HttpResponse()
    response.set_cookie("a", "123")  # 設置一個cookie
    cookie = response.COOKIES
    a = cookie.get("a", None)  # 獲取cookie
    response.write(a)
    return response
View Code

cookie是以明文的方式保存在客戶端的,若是有敏感的信息則不安全。

(三).HttpResponse的子類:JsonResponse

(1).返回json數據

(2).幫助用戶建立JSON編碼的響應

(3).參數data是字典對象

(4).JsonResponse的默認Content-Type爲application/json

(5).例

from django.http import JsonResponse

def jpTest(request):
    return JsonResponse({'ss':'123456'})
View Code

3、狀態保持

(1).http協議是無狀態的:每次請求都是一次新的請求,不會記得以前通訊的狀態

(2).客戶端與服務器端的一次通訊,就是一次會話實現狀態保持的方式:在客戶端或服務器端存儲與會話有關的數據

(3).存儲方式包括cookie、session,會話通常指session對象

(4).使用cookie,全部數據存儲在客戶端,注意不要存儲敏感信息

(5).推薦使用sesison方式,全部數據存儲在服務器端,在客戶端cookie中存儲session_id

(6).狀態保持的目的是在一段時間內跟蹤請求者的狀態,能夠實現跨頁面訪問當前請求者的數據

(7).注意事項:不一樣的請求者之間不會共享這個數據,與請求者一一對應

 

4、會話(session)

session是保存在服務端的,使用sessionid對應服務端中的session,sessionid則保存在cookie中。

cookie對應sessionid,sessionid對應服務端的session

(一).啓用session

(1).檢查settings.py文件

檢查settings.py文件是否有下面這些屬性

# 沒有的話,就添加

# INSTALLED_APPS 列表中:
'django.contrib.sessions',

# MIDDLEWARE_CLASSES 列表中:
'django.contrib.sessions.middleware.SessionMiddleware',
View Code

(二).使用session

(1).啓用會話後,每一個HttpRequest對象將具備一個session屬性,它是一個類字典對象

(2).get(key, default=None):根據鍵獲取會話的值

(3).clear():清除全部會話

(4).flush():刪除當前的會話數據並刪除會話的Cookie

(5).del request.session['member_id']:刪除會話

(三).session保持用戶登陸的例子

(1).視圖函數

from django.shortcuts import render, HttpResponse, redirect, reverse


# Create your views here.

def session_index(request):
    """
    首頁
    :param request:
    :return:
    """
    login_status = request.session.get("username", "你未登陸,請登陸!")
    return render(
        request,
        "ts11/session_index.html",
        context={
            "login_status": login_status,
        },
    )


def session_login(request):
    """
    登陸頁面
    用session實現登陸
    :param request:
    :return:
    """
    if request.method == "GET":
        return render(request, "ts11/session_login.html")
    elif request.method == "POST":
        request.session["username"] = request.POST.get("username")
        return redirect(reverse("index"))
    else:
        return HttpResponse("無效的請求")


def session_login_out(request):
    """
    註銷
    清空session
    :param request:
    :return: 清除session後,直接重定向,回到首頁
    """
    request.session.flush()
    return redirect(reverse("index"))
View Code

(2).url配置

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r"^session_index/$", views.session_index, name="index"),
    url(r"^session_login/$", views.session_login, name="login_in"),
    url(r"^session_login_out/$", views.session_login_out, name="login_out"),
]
View Code

(3).模板

# session_index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>session_index</title>
</head>
<body>
你好!{{ login_status }}<br>
<a href="{% url "login_in" %}">登陸</a>
<br><br>
<a href="{% url "login_out" %}">註銷</a>
</body>
</html>


# session_login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>session_login</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    用戶名:<input type="text" name="username"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>
View Code

(四).會話過時時間

(1).set_expiry(value):設置會話的超時時間

(2).若是沒有指定,則14天后過時

(3).若是value是一個整數,會話將在values秒沒有活動後過時

(4).若果value是一個imedelta對象,會話將在當前時間加上這個指定的日期/時間過時

(5).若是value爲0,那麼用戶會話的Cookie將在用戶的瀏覽器關閉時過時

(6).若是value爲None,那麼會話永不過時

(7).在視圖函數中設置過時的示例

#------------view.py--------------
def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        username = request.POST.get('username')
        request.session['username']=username
        request.session.set_expiry(0)  # 關閉瀏覽器就過時
        return redirect(reverse('ts11_home'))
View Code

(8).settings.py中的配置

# 是否關閉瀏覽器使得Session過時,默認是False
SESSION_EXPIRE_AT_BROWSER_CLOSE = False   

#是否每次請求都保存Session,默認修改以後才保存
SESSION_SAVE_EVERY_REQUEST = False

# Session的cookie失效日期,默認是2周
SESSION_COOKIE_AGE = 1209600
View Code

(五).如何查看cookie和session

我是chrome的忠實粉,因此只看了Google Chrome的設置。

步驟:設置 - 高級 - 內容設置 - Cookie - 查看全部Cookie和網站數據 - 找到你本身的IP或域名

 


 

表單篇

 

django中的表單不是html中的那個<form>表單。而是app中的forms.py這個文件所生成的(這個文件名不像templates那樣嚴格,能夠寫form.py也能夠寫forms.py,但基本是寫forms)

django的表單一般是用來驗證數據的合法性。不多用來生成HTML代碼(django生成的表單較難調整樣式)

 

1、使用表單

(一).表單經常使用的屬性、方法

(1).建立一個forms.py的文件,放在app當中,而後在裏面寫表單

(2).表單是經過類實現的,繼承自forms.Form,而後在裏面定義要驗證的字段

(3).在表單中,建立字段跟模型是如出一轍的,可是沒有null=True或者blank=True等這幾種參數了,有的參數是required=True/False

(4).使用is_valid()方法能夠驗證用戶提交的數據是否合法,並且HTML表單元素的name必須和django中的表單的name保持一致,不然匹配不到

(5).is_bound屬性:用來表示form是否綁定了數據,若是綁定了,則返回True,不然返回False

(6).cleaned_data:這個是在is_valid()返回True的時候,保存用戶提交上來的數據.

(7).示例

# forms.py

from django import forms


class RegisterForm(forms.Form):
    """
    驗證註冊頁面的form
    """
    username = forms.CharField(
        max_length=100, min_length=6,
        error_messages={
            "min_length": "用戶名不能少於6位",
        }
    )
    password = forms.CharField(
        max_length=100, min_length=6,
        widget=forms.PasswordInput(),
        error_messages={
            "min_length": "密碼不能少於6位",
        }
    )
    password_repeat = forms.CharField(
        max_length=100, min_length=6,
        widget=forms.PasswordInput(),
        error_messages={
            "min_length": "密碼不能少於6位",
        }
    )
    email = forms.EmailField()


class RegisterLogin(forms.Form):
    """
    驗證登陸頁面的form
    """
    username = forms.CharField(
        max_length=100, min_length=6,
        error_messages={
            "min_length": "用戶名不能少於6位",
        }
    )
    password = forms.CharField(
        max_length=100, min_length=6,
        widget=forms.PasswordInput(),
        error_messages={
            "min_length": "密碼不能少於6位",
        }
    )
View Code

(二).字段類型中的一些參數

這些參數會對頁面的輸入作一些限制條件

max_length  最大長度
min_length  最小長度
widget  負責渲染網頁上HTML 表單的輸入元素和提取提交的原始數據
attrs  包含渲染後的Widget 將要設置的HTML 屬性
error_messages 報錯信息
View Code

2、表單小案例

需求:實現註冊、登陸。

要求:使用djang的form進行表單驗證。

(一).寫模型

from django.db import models


# Create your models here.

class Register(models.Model):
    """
    註冊頁面的模型
    """
    username = models.CharField(max_length=100, unique=True)
    password = models.CharField(max_length=100)
    email = models.EmailField()

    def __str__(self):
        return "Register <username:{},password:{},email:{}>".format(
            self.username, self.password, self.email
        )
View Code

而後進行makemigrations和migrate

(二).寫forms.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# __author__ = "Jack"

from django import forms


class RegisterForm(forms.Form):
    """
    驗證註冊頁面的form
    """
    username = forms.CharField(
        max_length=100, min_length=6,
        error_messages={
            "min_length": "用戶名不能少於6位",
        }
    )
    password = forms.CharField(
        max_length=100, min_length=6,
        widget=forms.PasswordInput(),
        error_messages={
            "min_length": "密碼不能少於6位",
        }
    )
    password_repeat = forms.CharField(
        max_length=100, min_length=6,
        widget=forms.PasswordInput(),
        error_messages={
            "min_length": "密碼不能少於6位",
        }
    )
    email = forms.EmailField()


class RegisterLogin(forms.Form):
    """
    驗證登陸頁面的form
    """
    username = forms.CharField(
        max_length=100, min_length=6,
        error_messages={
            "min_length": "用戶名不能少於6位",
        }
    )
    password = forms.CharField(
        max_length=100, min_length=6,
        widget=forms.PasswordInput(),
        error_messages={
            "min_length": "密碼不能少於6位",
        }
    )
View Code

(三).寫視圖函數views.py

(1).導包

from django.shortcuts import render, HttpResponse, redirect, reverse

from .forms import *
from .models import *
View Code

(2).index()

def index(request):
    """
    首頁
    :param request:
    :return:
    """
    login_status = request.session.get("username", "請登陸")
    return render(
        request,
        "ts22/index.html",
        context={
            "login_status": login_status,
        },
    )
View Code

(3).register()

def register(request):
    """
    註冊頁面的視圖函數
    :param request:
    :return:
    """
    if request.method == "GET":
        return render(request, "ts22/register.html")
    elif request.method == "POST":
        form = RegisterForm(request.POST)  # 使用django的form進行驗證
        if form.is_valid():
            username = request.POST["username"]
            password = request.POST["password"]
            password_repeat = request.POST["password_repeat"]
            email = request.POST["email"]
            if password == password_repeat:
                Register.objects.create(username=username, password=password_repeat, email=email)
            else:
                return render(
                    request,
                    "ts22/register.html",
                    context={"error_message": "兩次密碼輸入的不一致,請檢查!", },
                )
        else:
            return render(request, "ts22/register.html", context={"error_message": form.errors, }, )
        return render(request, "ts22/register_success.html")  # 直接渲染模板,進行跳轉
    else:
        return render(request, "ts22/register.html")
View Code

(4).login()

def login(request):
    """
    登陸頁面的視圖函數
    :param request:
    :return:
    """
    if request.method == "GET":
        return render(request, "ts22/login.html")
    elif request.method == "POST":
        form = RegisterLogin(request.POST)
        if form.is_valid():
            form_data = form.cleaned_data
            username = form_data["username"]
            password = form_data["password"]
            try:
                Register.objects.get(username=username, password=password)  # get()沒有返回值是會報錯的
            except Register.DoesNotExist:
                return HttpResponse("登陸失敗,請檢查用戶名或密碼!")  # 用異常捕獲來檢驗是否登陸成功
            else:
                request.session["username"] = username  # 保存session
                return redirect(reverse("index"))
        else:
            return render(request, "ts22/login.html", context={"error_messages": form.errors}, )
    else:
        return HttpResponse("無效的請求")
View Code

(5).logout()

def logout(request):
    """
    註銷頁面的視圖函數
    :param request:
    :return: 註銷後直接回到首頁
    """
    request.session.flush()
    return redirect(reverse("index"))
View Code

(四).寫模板templates/ts22

(1).index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
你好,{{ login_status }}!
<br>
<a href="{% url "register" %}">註冊</a>
<br>
<a href="{% url "login" %}">登陸</a>
<br>
<a href="{% url "logout" %}">註銷</a>
</body>
</html>
View Code

(2).login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    用戶名:<input type="text" name="username">
    <br>
    密碼:<input type="password" name="password">
    <br>
    <input type="submit" value="登陸">
    {{ error_messages }}
</form>
</body>
</html>
View Code

(3).register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>register</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    用戶名:<input type="text" name="username" placeholder="請輸入用戶名">
    <br>
    密碼:<input type="password" name="password" placeholder="請輸入密碼">
    <br>
    確認密碼:<input type="password" name="password_repeat" placeholder="請確認密碼">
    <br>
    郵箱:<input type="email" name="email" placeholder="請輸入郵箱地址">
    <br>
    <input type="submit" value="當即註冊">
    {{ error_message }}
</form>
</body>
</html>
View Code

(4).register_success.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊成功</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .bigbox {
            width: 400px;
            height: 200px;
            text-align: center;
            border: 2px solid rgb(180, 9, 28);
            border-radius: 7px;
            position: absolute;
            margin: auto;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            box-shadow: lightgrey 3px 3px 3px;
        }

        .cell {
            position: relative;
            top: 50%;
            transform: translateY(-50%);
        }
    </style>
</head>
<body>
<div class="bigbox">
    <div class="cell">
        註冊成功!感謝您註冊成爲咱們的會員!
        <br>
        <span id="countdown_seconds">5</span>秒後,將會自動回到首頁!
        <br>
        若是瀏覽器沒有自動跳轉,<a href="{% url "index" %}">點此回到主頁</a>
    </div>
</div>
<script>
    window.onload = function () {
        let time = document.getElementById("countdown_seconds").innerText;
        let set = setInterval(function () {
            time--;
            if (time < 1) {
                {#<1就不會出現0了#}
                window.location = "{% url "index" %}";
            } else {
                document.getElementById("countdown_seconds").innerText = time;
            }
        }, 1000);
    }
</script>
</body>
</html>
View Code

(五).註冊路由

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r"^index/$", views.index, name="index"),
    url(r"^register/$", views.register, name="register"),
    url(r"^login/$", views.login, name="login"),
    url(r"^logout/$", views.logout, name="logout"),
]
View Code

(六).注意事項

(1).新的app不要忘記去總url中註冊

(2).新的app不要忘記去settings.py中的INSTALLED_APPS中註冊

 


 

中間件篇

 

中間件,顧名思義:中途做處理。能夠介入Django的請求和響應處理過程,修改Django的輸入或輸出。它針對的是request、response

 

1、自定義中間件

(一).在settings.py同級目錄下建立myself_middleware.py文件(中間件的命名隨意,但要符合python變量命名規則)

(二).寫入代碼

例如:

from ts22.models import *


def is_my_user_login(request):
    username = request.session.get("username", "")
    user = Register.objects.filter(username=username).first()

    if user:
        return {"login_or_not": user.username}
    else:
        return {"login_or_not": "請登陸"}
View Code

返回的必須是一個字典!

(三).把這個函數註冊進TEMPLATES中去

模型直接沿用了表單篇的小案例

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# __author__ = "Jack"

from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin

from ts22.models import *


class MyExceptionMiddleware(MiddlewareMixin):
    def process_exception(self, request, exception):
        return HttpResponse("程序出錯了:" + str(exception))


class RegisterMiddleware(MiddlewareMixin):
    def __init__(self, get_response):
        # 接收一個請求對象,也就是request
        self.get_response = get_response

    def __call__(self, request):
        # request到達view以前執行的代碼
        username = request.session.get("username", "")
        user = Register.objects.filter(username=username).first()
        if user:
            if not hasattr(request, "my_user"):
                setattr(request, "my_user", user.username)
        else:
            setattr(request, "my_user", "請登陸.this is from middleware")

        response = self.get_response(request)  # 返回響應

        """
        這塊代碼是response對象,到達瀏覽器以前執行的代碼
        """

        return response
View Code

(三).每一箇中間件組件是一個獨立的Python類,能夠在類中定義下面方法中的一個或多個

注意:它們的方法名都是固定的!

_init _:無需任何參數,服務器響應第一個請求的時候調用一次,用於肯定是否啓用當前中間件

process_request(request):執行視圖以前被調用,在每一個請求上調用,返回None或HttpResponse對象

process_view(request, view_func, view_args, view_kwargs):調用視圖以前被調用,在每一個請求上調用,返回None或HttpResponse對象

process_template_response(request, response):在視圖恰好執行完畢以後被調用,在每一個請求上調用,返回實現了render方法的響應對象

process_response(request, response):全部響應返回瀏覽器以前被調用,在每一個請求上調用,返回HttpResponse對象

process_exception(request,response,exception):當視圖拋出異常時調用,在每一個請求上調用,返回一個HttpResponse對象
View Code

(四).註冊

將(二)中的兩個類,註冊到settings.py中間件中的MISSLEWARE裏面去

(五).在視圖函數中使用中間件

def index(request):
    """
    首頁
    :param request:
    :return:
    """
    login_status = request.my_user
    return render(
        request,
        "ts22/index.html",
        context={
            "login_status": login_status,
        },
    )
View Code

(六).做用

後期須要加功能,直接加中間件處理了,不可能一個個視圖去改了。

若是有好多視圖須要同一個功能,中間件就很好用了。一處寫,整個項目都能用了。

 


 

上下文處理器篇

 

實質上就是視圖函數中的render(context={}),上下文處理器就是個模板變量,只針對模板。

 

1、自定義上下文處理器

(一).在settings.py同級目錄下建立myself_contextprocessor.py文件(命名隨意,但要符合python變量命名規則)

(二).寫入代碼

仍是沿用了表單篇的models

from ts22.models import *


def is_my_user_login(request):
    username = request.session.get("username", "")
    user = Register.objects.filter(username=username).first()

    if user:
        return {"login_or_not": user.username}
    else:
        return {"login_or_not": "請登陸"}
View Code

返回的必須是一個字典!

(三).把這個函數註冊進settings.py中的TEMPLATES去。

(四).使用它

直接去模板中,在你想要的地方,寫上{{ login_or_not }}

相關文章
相關標籤/搜索