• Django


    请求与响应篇

    一、HttpRequest对象

    服务器接收到http协议的请求后,会根据报文创建HttpRequest对象。视图函数的第一个参数(request)是HttpRequest对象在django.http模块中定义了HttpRequest对象的API

    所谓的API,在django中就是属性、方法。

    (一).HttpRequest对象的属性及方法

    属性:
    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对象

    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属性一样为一组,当控件被选中后会被提交,存在一键多值的情况

    二、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':'123455'})
    View Code

    三、状态保持

    (1).http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态

    (2).客户端与服务器端的一次通信,就是一次会话实现状态保持的方式:在客户端或服务器端存储与会话有关的数据

    (3).存储方式包括cookie、session,会话一般指session对象

    (4).使用cookie,所有数据存储在客户端,注意不要存储敏感信息

    (5).推荐使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储session_id

    (6).状态保持的目的是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据

    (7).注意事项:不同的请求者之间不会共享这个数据,与请求者一一对应

    四、会话(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).创建一个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

    二、表单小案例

    需求:实现注册、登录。

    要求:使用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__ = "Blue Margaret"
    
    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

    一、自定义中间件

    (一).在settings.py同级目录下创建myself_middleware.py文件(中间件的命名随意,但要符合python变量命名规则)

    (二).写入代码

    Ps:模型直接沿用了表单篇的小案例

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    # __author__ = "Blue Margaret"
    
    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中间件中

    (五).在视图函数中使用中间件

    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={}),上下文处理器就是个模板变量,只针对模板。

    一、自定义上下文处理器

    (一).在settings.py同级目录下创建myself_contextprocessor.py文件(命名随意,但要符合python变量命名规则)

    (二).写入代码

    Ps:还是沿用了表单篇的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

    返回的必须是一个字典!

    (三).把这个函数注册进去

    (四).使用它

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

  • 相关阅读:
    SSH 远程执行任务
    C# 创建压缩文件
    迁移 SQL Server 到 Azure SQL 实战
    在 Azure 上部署 Asp.NET Core Web App
    linux kill 命令
    VS 远程调试 Azure Web App
    Azure 基础:自定义 Table storage 查询条件
    NSOperation的使用细节 [2]
    NSOperation的使用细节 [1]
    [翻译] SSKeychain
  • 原文地址:https://www.cnblogs.com/quanquan616/p/9138748.html
Copyright © 2020-2023  润新知