• 【web开发】8、Django(3)


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


    前言

    提示:这里可以添加本文要记录的大概内容:

    例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、管理员

    1.表结构

    首先在models.py文件下定义Admin这个类,同时用djando命令生成数据库表(python manage.py makemigrations;python manage.py migrate)数据库下才有app01_admin这个数据表。

    #models.py
    class Admin(models.Model):
        """管理员"""
        username = models.CharField(verbose_name="用户名",max_length=32)
        password = models.CharField(verbose_name="密码",max_length=64)
    
        def __str__(self):
            return self.username      #连接表中所显示的内容
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.layout.html文件下添加管理员账号的导航

    <li><a href="/admin/list/">管理员账户</a></li>
    
    • 1

    3.urls.py文件(POST请求传递nid)

         path('admin/list/', admin.admin_list),
         path('admin/add/', admin.admin_add),
         path('admin//edit/', admin.admin_edit),
         path('admin//delete/', admin.admin_delete),
         path('admin//reset/', admin.admin_reset),
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.form.py文件(密码加密,确认密码,重置密码与原密码要求不一致)

    from django import forms
    from django.core.exceptions import ValidationError
    
    from app01 import models
    from app01.utils.encrypt import md5
    from app01.utils.bootstrap import BootstrapModelForm
    
    class AdminModelForm(BootstrapModelForm):
        confirm_password = forms.CharField(
            label="确认密码",
            widget=forms.PasswordInput(render_value=True))
    
        class Meta:
            model = models.Admin
            fields = ["username", 'password', 'confirm_password']
            widgets = {
                "password": forms.PasswordInput(render_value=True)
                #render_value=True密码错误也不会置空
            }
    
        def clean_password(self):
            pwd = self.cleaned_data.get("password")
            return md5(pwd)
    
        def clean_confirm_password(self):
            pwd = self.cleaned_data.get("password")
            confirm = md5(self.cleaned_data.get("confirm_password"))
            if confirm != pwd:
                raise ValidationError("密码不一致")
            # 返回的数值保存在数据库中
            return confirm
    
    class AdminEditModelForm(BootstrapModelForm):
        class Meta:
            model = models.Admin
            fields = ['username']  # 只允许编辑用户名,其他信息不能编辑
    
    class AdminResetModelForm(BootstrapModelForm):
        confirm_password = forms.CharField(
            label="确认密码",
            widget=forms.PasswordInput(render_value=True))
    
        class Meta:
            model = models.Admin
            fields = ["password", "confirm_password"]
            widgets = {
                "password": forms.PasswordInput(render_value=True)
            }
    
        def clean_password(self):
            pwd = self.cleaned_data.get("password")
            md5_pwd = md5(pwd)
    
            # 去数据库校验当前密码和输入密码是否一致
            exists = models.Admin.objects.filter(id=self.instance.pk, password=md5_pwd).exists()
            if exists:
                raise ValidationError("与之前密码一致")
            return md5_pwd
    
        def clean_confirm_password(self):
            pwd = self.cleaned_data.get("password")
            confirm = md5(self.cleaned_data.get("confirm_password"))
            if confirm != pwd:
                raise ValidationError("密码不一致")
            # 返回的数值保存在数据库中
            return confirm
    
    • 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
    • 64
    • 65
    • 66

    5.admin.py文件

    (用户是否存在/登录、搜索、分页、编辑前确认所编辑对象存在于数据库中、编辑时显示编辑前字段的信息、添加页面相同时写入模板文件传递标题)

    from django.shortcuts import render, redirect
    
    from app01 import models
    from app01.utils.pagination import Pagination
    from app01.utils.form import AdminModelForm,AdminEditModelForm,AdminResetModelForm
    
    
    def admin_list(request):
        """管理员列表"""
        
        """检查用户是否登录,已登录继续走下去,未登录,跳转到登录页面
        用户发来请求,获取cookie随机字符串,拿着随机字符串看session中有没有"""
       #是否登录
        info = request.session["info"]
        if not info:
            return redirect("/login/")
        # 搜索
        data_dict = {}
        search_data = request.GET.get('q', "")
        if search_data:
            data_dict["username__contains"] = search_data
        # 根据搜索条件去数据库获取
        queryset = models.Admin.objects.filter(**data_dict)
        # 分页
        page_object = Pagination(request, queryset, page_size=3)
        context = {
            'queryset': page_object.page_queryset,
            'page_string': page_object.html(),
            'search_data': search_data,
        }
        return render(request, "admin_list.html", context)
    
    def admin_add(request):
        """添加管理员"""
        title = "新建管理员"
        if request.method == "GET":
            form = AdminModelForm()
            #change.html为添加模板
            return render(request, 'change.html', {"form": form, "title": title})
        form = AdminModelForm(data=request.POST)
        if form.is_valid():
            form.save()
            return redirect('/admin/list')
        return render(request, 'change.html', {"form": form, "title": title})
    
    def admin_edit(request, nid):
        """编辑管理员"""
        row_object = models.Admin.objects.filter(id=nid).first()
        if not row_object:
            return render(request, "error.html", {"msg": "数据不存在"})
        title = "编辑管理员"
    
        if request.method == "GET":
            form = AdminEditModelForm(instance=row_object)  # 输入框内显示的默认值
            return render(request, 'change.html', {"form": form, "title": title})
        form = AdminEditModelForm(data=request.POST, instance=row_object)
        if form.is_valid():
            form.save()
            return redirect("/admin/list")
        return render(request, 'change.html', {"form": form, "title": title})
    
    def admin_delete(request, nid):
        models.Admin.objects.filter(id=nid).delete()
        return redirect('/admin/list/')
    
    def admin_reset(request, nid):
        """重置密码"""
        row_object = models.Admin.objects.filter(id=nid).first()
        if not row_object:
            return redirect('/admin/list/')
        title = "重置密码-{}".format(row_object.username)
        if request.method == "GET":
            form = AdminResetModelForm()
            return render(request, 'change.html', {"form": form, "title": title})
        form = AdminResetModelForm(data=request.POST, instance=row_object)
        if form.is_valid():
            form.save()
            return redirect("/admin/list/")
        return render(request, 'change.html', {"form": form, "title": title})
    
    • 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
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    二、中间件(实现登录校验)

    #info用于验证用户是否登录过,以便能否访问其他页面
    在其他需要登录才能访问的页面中,都要加入:

    #是否登录
        info = request.session["info"]
        if not info:
            return redirect("/login/")
    
    • 1
    • 2
    • 3
    • 4

    1.中间件的作用

    可以在请求到达视图函数之前执行操作。这使得你可以在请求处理之前进行身份验证权限检查、日志记录等操作。

    在appo01目录下创建middleware目录,并创建auth.py文件
    在这里插入图片描述

    2.定义中间件

    #auth.py
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import redirect
    
    class AuthMiddleware(MiddlewareMixin):
        """中间件"""
        def process_request(selfself,request):
            #0.排除那些不需要登录就能访问的页面
            #request.path_info 获取当前用户请求的url  /login/
            if request.path_info in["/login/","/image/code/"]:
                return
    
            #1.读取当前访问的用户的session信息,如果能读到,说明已经登录过,可以继续向后走
            info_dict = request.session.get("info")
            print(info_dict)
            if info_dict:
                return
    
            #2.没有登录过,重新回到登录页面
            return redirect("/login/")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.应用中间件

    并在settings.py文件下的MIDDLEWARE中添加中间件auth.py的路径
    在这里插入图片描述

    4.在中间件的process_request方法

    #如果方法中没有返回值(返回None),继续向后走
    #如果有返回值HttpResponse\render\redirect,则不再继续向后执行

    三、图片验证码及登录界面

    1.图片验证码

    pip install pillow
    
    • 1
    def image_code(request):
        """生成图片验证码"""
        # 调用pillow函数,生成图片
        img, code_string = check_code()
        print(code_string)
        # 写入到自己的session中,以便后续获取验证码再进行校验
        request.session['imge_code'] = code_string
        # 给session设置60*60*24*7秒超时
        request.session.set_expiry(60 * 60 * 24 * 7)
        #内存文件BytesIO
        stream = BytesIO()
        img.save(stream, 'png')
        return HttpResponse(stream.getvalue())
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.登录界面

    POST提交需要添加: {% csrf_token %}
    消除浏览器自带提示:在form内添加 novalidate

    #html
    {% load static %}
    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
        <style>
            .account {
                width: 450px;
                border: 1px solid gray;
                height: 400px;
                margin-left: auto;
                margin-right: auto;
                margin-top: 150px;
                padding: 40px 20px 40px 20px;
                border-radius: 5px;
                box-shadow: 5px 5px 5px #aaa;
            }
    
            .account h1 {
                text-align: center;
                margin-top: 5px;
            }
        style>
    head>
    <body>
    <div class="account">
        <h1>用户登录h1>
        {#    <form method="post" action = "{% url 'admin' %}">#}
        <form method="post" novalidate>
            {% csrf_token %}
            <div >
                <label>用户名label>
                {{ form.username }}
                <span style="color: red;">{{ form.username.errors.0 }}span>
            div>
            <div class="form-group">
                <label>密码label>
                {{ form.password }}
                <span style="color: red;">{{ form.password.errors.0 }}span>
    
            div>
            <div class="form-group">
                    <div>
                        <label>图片验证码label>
                    div>
                    <div class="col-lg-7">
                        {{ form.code }}
                <span style="color: red;">{{ form.code.errors.0 }}span>
                    div>
                    <img data-v-66879da5="" alt="验证码"
                         src="/image/code/"
                         class="img-logo" style="margin-left: 20px">
                div>
            <div>
                <button type="submit" class="btn btn-primary" style="margin-top: 18px;">登 录button>
            div>
        form>
    
    div>
    
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js">script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js">script>
    body>
    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
    • 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
    • 64
    • 65
    • 66
    • 67
    • 68
    class LoginForm(BootstrapForm):
    #Form组件需要手动写字段
        username = forms.CharField(
            label="用户名",
            widget=forms.TextInput(),
            # widget=forms.TextInput(attrs={"class":"form-group"}),
            required=True  # 必填,不能为空
    
        )
        password = forms.CharField(
            label="密码",
            widget=forms.PasswordInput(render_value=True),
            required=True  # 必填,不能为空
        )
        code = forms.CharField(
            label="验证码",
            widget=forms.TextInput,
            required=True  # 必填,不能为空
        )
        class Meta:
            model = models.Admin
            fields = ['username', 'password']
        def clean_password(self):
            pwd = self.cleaned_data.get("password")
            return md5(pwd)
    
    
    def login(request):
        """登录"""
        if request.method == "GET":
            form = LoginForm()
            return render(request, 'login.html', {"form": form})
        form = LoginForm(data=request.POST)
        if form.is_valid():
            print(form.cleaned_data)#验证成功,获取用户名和密码
            user_input_code = form.cleaned_data.pop('code')
            code = request.session.get('imge_code')
            if code.upper() != user_input_code.upper():
                form.add_error("code", "验证码错误")  # 主动在password下添加错误提示
                return render(request, 'login.html', {"form": form})
            # 去数据库校验用户名和密码是否正确,获取用户对象
            admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
            if not admin_object:
                form.add_error("password", "用户名或密码错误")  # 主动在password下添加错误提示
                return render(request, 'login.html', {"form": form})
            # 用户名和密码正确
            # 网站生成随机字符串,写到用户浏览器的cookie中,在写入到session中
            request.session["info"] = {"id": admin_object.id, "name": admin_object.username}
            #info用于验证用户是否登录过,以便能否访问其他页面
            return redirect("/admin/list/")
        return render(request, 'login.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

    四、注销用户(退出登录)

    def logout(request):
        """注销"""
        request.session.clear()
        return redirect('/login/')
    
    • 1
    • 2
    • 3
    • 4
    登录完成,则{{ request.session.info.name }}一定存在,可以直接传到html中
    
    • 1
  • 相关阅读:
    BeanUtils.copyProperties:曾经是我的女神,现在是我的毒药。
    学生HTML个人网页作业作品:基于web在线汽车网站的设计与实现 (宝马轿车介绍)
    自学网络安全的三个必经阶段(含路线图),小白必看
    《PyTorch 2.0深度学习从零开始学》已出版
    从入门开始手把手搭建千万级Java算法测试-斐波那契额数列的三种实现方法比较
    解决:brew install xxx 时出现“No such file or directory @ rb_sysopen - ”
    spring Cloud笔记--服务治理Eureka
    三种插件开发模式,带你玩废tinymce
    wireshark 抓包工俱使用一
    ceph debug
  • 原文地址:https://blog.csdn.net/qq_46644680/article/details/132887512