• Django框架基本语法(二)


    Django 框架(二)

    六、 请求与响应

    官方文档地址:https://docs.djangoproject.com/en/4.0/ref/request-response/

    1、 HttpRequest

    1.1 介绍

    页面被请求,Django创建一个HttpRequest对象,该对象里有请求的源数据。django会加载适当的视图,将HttpRequest作为第一个参数传递给视图函数,每个视图负责返回一个HttpResponse对象。

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

    1.2 接口

    1.3 表单

    这里默认会将文件写入相应路径,同时提交表单,推荐使用post方式提交,更加安全

    index.html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>form表单</title>
    </head>
    <body>
    <form action="{% url 'student:index' %}" method="post"> {% csrf_token %} <!--如果action为空,则将数据提交给当前页面,使用csrf_token离开解决跨域问题-->
        <label for="username">用户名</label>
        <input type="text" name="username" id="username" placeholder="please input your name"/>
        <label for="pwd">密码</label>
        <input type="password" name="pwd" id="pwd" placeholder="please input your password">
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    csrf跨域问题:

    • django的配置中设置了跨站请求的限制,默认禁止的状态
    • form表单发送post请求时,服务端要求客户端加上csrfmiddlewatetoken字段,该字段的值为当前会话ID加上一个密钥的散列值。
    • 防止跨域请求

    解决方法:

    1. form表单后边加上{% csrf_token %},推荐使用这种方式

    2. 修改配置文件

      MIDDLEWARE = [
          'django.middleware.security.SecurityMiddleware',
          'django.contrib.sessions.middleware.SessionMiddleware',
          'django.middleware.common.CommonMiddleware',
          # 'django.middleware.csrf.CsrfViewMiddleware',  # 把这一行注释掉,不进行视图的csrf验证,防止其他网站伪造请求进行访问	
          'django.contrib.auth.middleware.AuthenticationMiddleware',
          'django.contrib.messages.middleware.MessageMiddleware',
          'django.middleware.clickjacking.XFrameOptionsMiddleware',
      ]
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    views.py

    from django.shortcuts import render
    from django.http import HttpResponse
    import json
    
    # Create your views here.
    # path("index/", views.index, name="index")  路由地址
    def index(request):
        """这里的操作只是测试,在实际中会对提交的密码和账户进行校验,成功返回首页面,失败返回登录页面"""
        if request.method == "POST":
            # 返回数据
            username = request.POST.getlist('username')  # 返回列表
            pwd = request.POST.getlist('pwd')  # 也可以通过get方法来获取,推荐使用getlist()
            resp = {'code': 200, 'username': username[0], "pwd": pwd[0]}
            return HttpResponse(json.dumps(resp), content_type="application/json")
        return render(request, "student/index.html")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    总结:

    1. GET:如其名,是从服务器获取数据,不会更改服务器的状态和数据,在URL中可携带参数
    2. POST:将一定数据发送给服务器,一般都会更改服务器的数据
    3. 相对来说,POST提交数据的方式比GET安全一点
    1.4 文件上传

    index.html修改成

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>form表单</title>
    </head>
    <body>
    <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %}
        <input type="file" name="file" multiple="multiple">  <!--可以进行多文件上传-->
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    views.py修改成

    from django.shortcuts import render
    from django.http import JsonResponse
    from CRM.settings import MEDIA_ROOT  # 导入配置文件,在配置文件中设置了文件存储路径
    # MEDIA_ROOT = os.path.join(BASE_DIR, 'static/media')
    from datetime import datetime
    import os
    
    
    # Create your views here.
    # path("index/", views.index, name="index")  路由地址
    def index(request):
        if request.method == "POST":
            file = request.FILES.getlist("file")  # 建议使用getlist,当然,也可以使用get方法
            day_dir_name = datetime.now().strftime("%Y%m%d")  # 定义目录名
            day_dir = os.path.join(MEDIA_ROOT, day_dir_name)  # 设置路径
            # 创建路径,存在则不创建
            if not os.path.exists(day_dir):
                os.mkdir(day_dir)
            for file in files:
                with open(f"{day_dir}/{file.name}", "wb") as f:
                    for line in file:
                        f.write(line)  # 防止文件过大,进行逐行逐行写入
            return JsonResponse({"code": 200}, content_type="application/json")
        return render(request, "student/index.html")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2、 HttpResponse

    2.1 常用方法

    在这里插入图片描述

    当进行前后端分离的时候,可以需要将我们的响应数据传递给前端页面,然后由前端页面进行渲染,可以使用类视图,我们暂时学的是前后端不分离,使用context参数进行上下文管理

    同时,响应的更多方法,请到官网进行查看!

    2.2 类视图
    from django.views import View
    from django.http import JsonResponse
    
    # path("test/", views.ViewTest.as_view(), name="test"),  # 注册类视图的方法,这个主要用于前后端分离开发,作为后端的响应
    class ViewTest(View):
        def get(self, request):
            return JsonResponse({"code": 200, "data": {"page": "1", "title": "test文档"}})  # 将我们后端的数据进行封装成JSON数据后,传递给前端进行渲染
    
        def post(self, request):
            return JsonResponse({"code": 200, "data": {"name": "lihua", "age": 1}})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    2.3 Cookies

    HTTP(超文本传输协议)是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。

    服务器无法区分请求是哪个客户端发送过来的,故这时候就可以使用Cookies来区分了。客户端向服务器发送请求,服务器在http协议加上请求头,通过响应,传送并保存在客户端,客户端再次访问时,就会自动带上这个cookie。

    from django.http import JsonResponse, HttpResponse
    
    # 这里我们使用类视图来演示
    class ViewTest(View):
        def get(self, request):
            if not request.COOKIES.get("name"):  # 如果没有cookies,设置cookies,
                resp = HttpResponse()  # 创建一个请求
                resp.set_cookie("name", "lihua")  # 设置cookies,可以通过 max_age 设置cookies的有效时间,单位是秒
                resp["headers"] = "xxxxx"  # 设置 Response Headers
                resp.content = json.dumps({"code": 200, "msg": "登录成功"})  # 设置返回的内容
                resp.content_type="application/json"  # 设置返回数据的类型
                return resp  # 返回响应
            return JsonResponse({"code": 200})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    但是这个cookies没有进行加密,容易篡改,如何解决呢?我们使用session来进行会话的加密。

    3、 Session

    浏览器存储cookie的方式不太安全,那有没有更好些的来存储登入状态的方式呢?

    使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储session_id

    session基于cookierequest.session.get()

    注意:

    • 使用前记得查看是否注册sessionsapp

      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',  # session的app
          'django.contrib.messages',
          'django.contrib.staticfiles',
      ]
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      . 一般来说,sessionapp的注册好的

    • 使用前也需要查看是否添加session的中间件

      MIDDLEWARE = [
          'django.middleware.security.SecurityMiddleware',
          'django.contrib.sessions.middleware.SessionMiddleware',  # session的中间件
          'django.middleware.csrf.CsrfViewMiddleware',
          'django.middleware.common.CommonMiddleware',
          'django.contrib.auth.middleware.AuthenticationMiddleware',
          'django.contrib.messages.middleware.MessageMiddleware',
          'django.middleware.clickjacking.XFrameOptionsMiddleware',
      ]
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    • 同时,也需要对session进行数据库的迁移

      python manage.py makemigrations sessions  # 对sessions数据库进行迁移
      python manage.py migrate sessions  # 使得迁移生效
      
      • 1
      • 2

      数据库中主要存储session_key,用来设置cookies

    比如,登录状态的保持

    def login(request):
        if request.method == "POST":
            data = request.POST
            user = data.get("username")
            pwd = data.get("password")
            if user == "kun" and pwd == "1":
                # 把用户名设置到session中去
                request.session.update({
                    "user": user,  # 这个为敏感信息,故需要保存到session中
                })
                return redirect("student:index")
        return render(request, "student/login.html")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    删除当前的状态:request.session.flush()

    设置会话过期时间:

    request.session.set_expiry(1)  # 设置过期时间为1秒
    
    • 1

    通过配置文件来配置会话过期时间:

    SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得session过期,默认是False
    
    SESSION_SAVE_EVERY_REQUEST = False  # 是否每次请求都保存Session,默认修改之后才保存
    
    SESSION_COOKIE_AGE = 12.96000  # Session的cookie失效日期,默认是2周
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4、 分页器

    Django中内置了分页的对象

    分页功能位于django.core.paginator模块。

    Paginator提供包含一些对象的列表,以及你想每一页显示几条,比如每页5条、10条、20条、100条等等,它就会为你提供访问的一系列API方法,示例如下:

    >>> from django.core.paginator import Paginator
    >>> objects = ['john', 'paul', 'george', 'ringo']
    >>> p = Paginator(objects, 2)  # 对objects进行分页,虽然objects只是个字符串列表,但没关系,一样用。每页显示2条。
    
    >>> p.count   # 对象个数
    4
    >>> p.num_pages  # 总共几页
    2
    >>> type(p.page_range)  # `` in Python 2.
    <class 'range_iterator'>
    >>> p.page_range  # 分页范围
    range(1, 3)
    
    >>> page1 = p.page(1) # 获取第一页
    >>> page1
    <Page 1 of 2>
    >>> page1.object_list # 获取第一页的对象
    ['john', 'paul']
    
    >>> page2 = p.page(2)
    >>> page2.object_list
    ['george', 'ringo']
    >>> page2.has_next()  # 判断是否有下一页
    False
    >>> page2.has_previous()# 判断是否有上一页
    True
    >>> page2.has_other_pages() # 判断是否有其它页
    True
    >>> page2.next_page_number() # 获取下一页的页码
    Traceback (most recent call last):
    ...
    EmptyPage: That page contains no results
    >>> page2.previous_page_number() # 获取上一页的页码
    1
    >>> page2.start_index() # 从1开始计数的当前页的第一个对象
    3
    >>> page2.end_index() # 从1开始计数的当前页最后1个对象
    4
    
    >>> p.page(0)  # 访问不存在的页面
    Traceback (most recent call last):
    ...
    EmptyPage: That page number is less than 1
    >>> p.page(3) # 访问不存在的页面
    Traceback (most recent call last):
    ...
    EmptyPage: That page contains no results
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    简单地说,使用Paginator分四步走:

    • 使用任何方法,获取要展示的对象列表QuerySet
    • 将对象列表和每页展示数量传递给Paginator,返回一个分页对象
    • 调用该对象的各种方法,获取各种分页信息
    • 在HTML模板中,使用上面的分页信息构建分页栏

    七、 表单类

    1、 普通表单

    #!/usr/bin/python3
    # -*- coding: UTF-8 -*-
    __author__ = "A.L.Kun"
    __file__ = "form.py"
    __time__ = "2022/8/29 18:44"
    
    from django.shortcuts import render
    from django import forms
    
    
    class RegisterForm(forms.Form):
        """创建一个普通表单"""
        username = forms.CharField(label="用户名", max_length=20)
        pwd = forms.CharField(
            label="密码",
            max_length=8,
            min_length=6,
            widget=forms.PasswordInput(attrs={
                "placeholder": "请输入6~8位的密码"  # 设置表单的一些属性,可以设置类名等
            }),  # 设置输入框类型,默认为文本输入框
            error_messages={
                "min_length": "密码长度小于六位",
                "max_length": "密码长度大于八位"
            },  # 设置报错信息
        )
        pwd_repeat = forms.CharField(
            label="密码",
            widget=forms.PasswordInput(attrs={
                "placeholder": "请再次输入密码",
            }),
            error_messages={
                "min_length": "密码长度小于六位",
                "max_length": "密码长度大于八位"
            }  # 设置报错信息
        )
        email = forms.EmailField(required=False)  # 邮箱字段
    
        def clean(self):
            """"扩展校验功能,使得多个字段可以相互检验"""
            cleaned_data = super(RegisterForm, self).clean()  # 继承父类的clean方法
            # 扩展校验功能
            pwd = cleaned_data.get("pwd")
            pwd_ = cleaned_data.get("pwd_repeat")
            if pwd_ != pwd:
                msg = "两次密码不一致"
                self.add_error("pwd_repeat", msg)
    
    
    # path("", form.register, name="register")  # 注册路由
    def register(request):
        if request.method == "GET":
            form = RegisterForm()
        if request.method == "POST":
            data = request.POST
            form = RegisterForm(data)  # 构建一个填充好数据的对象
            if form.is_valid():
                # 判断校验是否成功,成功返回True
                username = form.cleaned_data.get("username", None)  # 从校验后的数据中,获取用户名
                print("用户名为", username)
    
        return render(request, "student/register.html", {
            "form": form,
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    创建表单的参数:

    • max_length:最大长度
    • min_length:最小长度
    • widget:负责渲染网页上HTML表单的输入元素和提取提交的原始数据
    • attrs:包含渲染后的Widget将要设置的HTML属性
    • error_messages:报错信息
    • validators:验证器

    可以参考我以前的博客中flask的表单验证,原理大概相同

    2、 模型表单

    官方文档地址:https://docs.djangoproject.com/zh-hans/4.0/topics/forms/modelforms/

    使用示例:

    from django.shortcuts import render
    from django import forms
    from django.db import models
    
    class Student(models.Model):
        """我们创建的模型类"""
        name = models.CharField("姓名", max_length=20, )  # verbose_name 用来设置字段前边的标签文字
        age = models.SmallIntegerField()
        SEX_CHOICE = (
            [0, "女"],
            [1, "男"]
        )
        sex = models.SmallIntegerField(choices=SEX_CHOICE, default=1)  # 其生成字段后,是一个下拉框
        qq = models.CharField(max_length=20, unique=True, error_messages={
            "unique": "qq号码重复"  # 设置报错信息
        })
        phone = models.CharField(max_length=20, unique=True)
        c_time = models.DateTimeField("创建时间", auto_now_add=True)
        e_time = models.DateTimeField("修改时间", auto_now=True)
        is_delete = models.BooleanField(default=False)  # 逻辑删除,False代表没删除
        grade = models.ForeignKey("Grade", on_delete=models.SET_NULL, null=True)
    
        def __str__(self):
            return f"{self.name}-{self.age}"
    
    
    class StudentForm(forms.ModelForm):
        class Meta:
            """在这里指定要映射的模型类"""
            model = Student  # 指定我们创建的学生模型
            # fields = "__all__"  # 所有字段都进行展示
            exclude = ["is_delete"]  # 指定不需要展示的字段
            widgets = {
                "sex": forms.RadioSelect(attrs={})  # 设置字段类型
            }
        def clean_qq(self):
            """对单个字段进行校验"""
            data = self.cleaned_data  # 校验后的数据,再对该字段进行校验
            if not data.isdigit():
                self.add_error("qq", "你输入的qq号码有问题")
            return data  # 要记得将数据返回
    
    
    def register(request):
        if request.method == "GET":
            form = StudentForm()
        if request.method == "POST":
            data = request.POST
            student = None  # 获取到学生对象
            form = StudentForm(data, instance=student)  # 构建一个填充好数据的对象,instance参数,覆盖原来的数据
            if form.is_valid():
                # 判断校验是否成功,成功返回True
                username = form.cleaned_data.get("username", None)  # 从校验后的数据中,获取用户名
                print("用户名为", username)
    
        return render(request, "student/register.html", {
            "form": form,
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    表单属性:

    from student.form import *
    forms = StudentForm() 
    for form in forms:
    	print(form.label)  # 获取字段对应的标签
        print(form.id_for_lable)  # 获取标签对应的id
        form.as_widget(attrs={
            "class": "class_str"
        })  # 使用这个方法,给该字段增加样式、属性
        print(form.errors)  # 获取报错信息
        print(form.value)  # 获取该字段的值
    # 这些属性可以用来自定义我我们的表单,使其个性化
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    八、 中间件

    django中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

    django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量**,**其中每一个元素就是一个中间件

    官方网站地址:https://docs.djangoproject.com/zh-hans/4.1/topics/http/middleware/

    1、 创建中间件

    顾名思义:请求送入之前和响应送出之前对请求和响应进行处理的组件

    中间件的命名和存储是可以任意的,只要是可以导入就行

    #!/usr/bin/python3
    # -*- coding: UTF-8 -*-
    __author__ = "A.L.Kun"
    __file__ = "middleware.py"
    __time__ = "2022/8/30 19:24"
    
    """使用装饰器作为中间件"""
    
    
    # 函数中间件
    def simple_middleware(get_response):
        """get_response参数名不可以修改"""
    	print("初始化")
        def middleware(request):
            print("视图函数调用之前,进行检验")
            response = get_response(request)  # 视图函数执行
            print("视图函数调用之后,进行检验")
            return response
    
        return middleware
    
    
    # 类中间件
    class SimpleMiddleware:
        """也可以使用类来作为装饰器"""
    	print("初始化")
        def __init__(self, get_response):
            self.get_response = get_response
            print("初始化")
    
        def __call__(self, request):
        	print("请求前")
            if "chrome" not in request.META.get("HTTP_USER_AGENT").lower():
                "如果不是使用Chrome浏览器,则拒绝访问"
                return HttpResponseForbidden()
            response = self.get_response(request)
            print(response)
            return response  # 将响应返回
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    2、 注册中间件

    我们需要在配置文件中,注册我们自定义的中间件

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'student.middleware.SimpleMiddleware',  # 注册类中间件
        'student.middleware.simple_middleware'  # 注册函数中间件
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    九、 上下文处理器

    1、 创建

    #!/usr/bin/python3
    # -*- coding: UTF-8 -*-
    __author__ = "A.L.Kun"
    __file__ = "customer_context.py"
    __time__ = "2022/8/30 20:08"
    
    
    def my_name(request):
        return {
            "name": "fei"  # 将name对应的值添加到全局变量中,这个变量可以通过request中的数据进行获取
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2、 注册

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates'), ],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                    'student.customer_context.my_name',  # 注册创建的上下文处理器
                ],
            },
        },
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    所有页面共用的变量,如果同时存在,优先使用context中的变量

    十、 管理系统

    1、 配置

    要求

    1. app注册
    2. 中间件注册
    3. 路径配置

    根据路径访问管理员站点:http://127.0.0.1:1236/admin/

    创建管理员账号:在项目根目录下运行shell

    python manage.py createsuperuser
    
    • 1

    根据要求来创建超级用户

    2、 管理模型

    studentapp中,来注册我们的模型,使得我们可以通过管理员用户来修改:

    Django提供了admin.ModelAdmin

    通过定义ModelAdmin的子类,来定义模型在Admin界面的显示方式

    • 列表页属性

      list_display:显示字段,可以点击列头进行排序

      list_filter:过滤字段,过滤框会出现在右侧

      search_fields:搜索字段,搜索框会出现在上侧

      list_per_page:分页,分页框会出现在下侧

    • 添加、修改页属性

      fields:属性的先后顺序

      fieldsets:属性分组

    注意:上面两个属性,二者选一

    from django.contrib import admin
    from .models import Student, StudentDetail
    
    
    # Register your models here.
    
    # 自定义
    class StudentAdmin(admin.ModelAdmin):
        list_display = ['id', 'name', 'sex', 'age', 'qq', 'phone']  # 指定显示字段
        list_display_links = ['name', 'sex']  # 指定跳转详情字段
        search_fields = ['name', 'qq', 'phone']  # 自定义搜索字段
        list_filter = ['sex']  # 过滤
        list_per_page = 5  # 每页显示数量
    
        # fields = ['age'] # 只允许修改的字段,和字段分组设置二选一
        # exclude = []  # 排除字段
        # 分组设置
        fieldsets = [
            (None, {'fields': ['name', 'sex']}),
            ('详细信息', {'fields': ['age', 'qq', 'phone']}),
            ('设置', {'fields': ['is_delete']}),
        ]
    
    
    admin.site.register(Student, StudentAdmin)  # 注册自定义模型
    admin.site.register(StudentDetail)  # 注册模型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    3、 auth

    3.1 数据表

    auth系统中的数据表

    UserUser是auth模块中维护用户信息的关系模式(继承了models.Model), 数据库中该表被命名为auth_user.

    GroupUser对象中有一个名为groups的多对多字段, 多对多关系由auth_user_groups数据表维护。Group对象可以通过user_set反向查询用户组中的用户。

    PermissionDjangoauth系统提供了模型级的权限控制, 即可以检查用户是否对某个数据表拥有增(add), 改(change), 删(delete)权限。

    3.2 验证系统

    配置文件讲解:

    INSTALLED_APPS = [
        'django.contrib.admin',  # 管理系统
        'django.contrib.auth',  # 权限系统
        'django.contrib.contenttypes',  # 把权限和模型关联起来
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'student'
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',  # 会话管理
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',  # 权限管理
        'django.contrib.messages.middleware.MessageMiddleware',  
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    注意:使用权限管理前,需要对模型进行迁移

    用户身份验证系统:

    用户身份验证系统:

    1. 身份验证:验证用户是否是用户

    2. 授权:决定用户做什么

    当前登录用户,是一个user对象,或者是一个AnonymousUser匿名用户实例,它会被存储在模板变量{{ user }}

    登录功能的实现:

    from django.contrib.auth import authenticate  # 对用户进行校验
    from django.contrib.auth import login as login_  # 进行登录,反正重名
    
    # path("", views.login, name="login")
    def login(request):
        # 判断是否登录
        if request.user.is_authenticated:  # 匿名用户返回false
            return redirect("student:index")
    
        if request.method == "POST":
            data = request.POST
            user = data.get("username")
            pwd = data.get("password")
            usr = authenticate(username=user, password=pwd)  # 如果验证失败,返回空;验证正确,返回一个用户对象
            if usr:  # 如果验证正确
                # 把用户名设置到session中去
                login_(request, usr)  # 将请求与用户关联起来
                return redirect("student:index")
        return render(request, "student/login.html")
    
    # path("/", views.login, name="login")
    def login_out(request):
        logout(request)  # 登出功能
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    登录验证:

    from django.contrib.auth.decorators import login_required
    from django.utils.decorators import method_decorator  # 将函数装饰器,转换为方法装饰器
    from django.views import View
    
    # Create your views here.
    @method_decorator(login_required)  # 进行登录验证
    class Register(View):
        def get(self, request):
            return "正在注册"
    
    @login_required  # 对是否登录进行验证,如果没有登录,跳转到登录页面
    def index(request):
        students = None  # 声明学生为空,查看post请求是否得到数据
        name = request.session.get("user", "游客")
        search = ''  # 默认搜索内容为空
        if request.method == "POST":
            search = request.POST.get("search", "").strip()  # 获取到数据
            if search:  # 如果search有值,则筛选,否则返回全部数据
                if search.isdigit():
                    students = Student.objects.filter(Q(qq=search) | Q(phone=search), is_delete=False)
                else:
                    students = Student.objects.filter(name=search, is_delete=False)
        if not students:
            students = Student.objects.filter(is_delete=False)
    
        section = "学生列表"
        return render(request, "student/index.html", context={
            "section": section,
            "students": students,
            "search_val": search,
            "name": name,
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    登录页面的路径在配置文件中配置:

    from django.urls import reverse_lazy
    
    LOGIN_URL = reverse_lazy("student:login")  # 懒加载
    
    • 1
    • 2
    • 3

    登录常用接口

    create_user 创建用户   
    authenticate 验证登录
    login 记住用户的登录状态
    logout 退出登录
    is_authenticated 判断用户是否登录
    login_required 判断用户是否登录的装饰器
    permission_required 权限验证装饰器
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    3.3 User模型

    User模型常用属性和方法:

    User对象有两个多对多字段:groupsuser_permissionsUser对象可以通过他们访问管理对象

    3.4 Group模型
    # user 为登录用户
    # 组操作
    user.groups.add(g2)  # 将用户添加到g2组
    user.groups.clear()  # 清空用户添加的组
    user.groups.set([g1, g2])  # 将用户添加到g1, g2组
    user.groups.remove(g1, g2)  # 将用户从g1, g2组中移除
    
    g1.user_set.add()  # 通过反向代理来把用户添加到组中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    3.5 Permission模型
    # user 为登录用户
    # 权限操作
    user.user_permissions.set([25,26,27,28])	# 设置
    user.user_permissions.remove(25,28)  # 移除
    user.user_permissions.add(25,28)  # 添加
    user.user_permissions.clear()  # 清空,对应功能的id
    # 对组进行权限操作
    gl.permissions.add(permission)  # 添加某个权限
    
    # 查看用户是否有某个app下某个模型的某个操作功能(增add删delete改change查view)
    user.has_perm('student.view_student')  # app.add_模型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    权限会被存储在模板变量{{ perms }}

  • 相关阅读:
    计算机毕业设计javaweb理发店预约网站源码
    Chia(奇亚)挖矿,投资价值几何 2021-04-18
    Python Pandas数据处理作图——霍尔效应
    2022杭电多校4
    uniapp—day02
    五一“捡钱”,就在这几天!国债逆回购最佳时点来了,如何躺赚6天利息?来看操作攻略
    用Python画出圣诞树,瞧瞧我这简易版的吧
    Hive知识梳理(好文)
    C-DS二叉树_另一棵树的子树
    【递归、搜索与回溯算法】第三节.21. 合并两个有序链表和206. 反转链表和24. 两两交换链表中的节点
  • 原文地址:https://blog.csdn.net/qq_62789540/article/details/126630109