【web开发】8、Django(3)

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

文章目录


前言

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

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


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

一、管理员

1.表结构

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

python 复制代码
#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      #连接表中所显示的内容

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

python 复制代码
<li><a href="/admin/list/">管理员账户</a></li>

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

python 复制代码
     path('admin/list/', admin.admin_list),
     path('admin/add/', admin.admin_add),
     path('admin/<int:nid>/edit/', admin.admin_edit),
     path('admin/<int:nid>/delete/', admin.admin_delete),
     path('admin/<int:nid>/reset/', admin.admin_reset),

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

python 复制代码
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

5.admin.py文件

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

python 复制代码
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})

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

#info用于验证用户是否登录过,以便能否访问其他页面

在其他需要登录才能访问的页面中,都要加入:

python 复制代码
#是否登录
    info = request.session["info"]
    if not info:
        return redirect("/login/")

1.中间件的作用

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

在appo01目录下创建middleware目录,并创建auth.py文件

2.定义中间件

python 复制代码
#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/")

3.应用中间件

并在settings.py文件下的MIDDLEWARE中添加中间件auth.py的路径

4.在中间件的process_request方法

#如果方法中没有返回值(返回None),继续向后走

#如果有返回值HttpResponse\render\redirect,则不再继续向后执行

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

1.图片验证码

python 复制代码
pip install pillow
python 复制代码
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())

2.登录界面

POST提交需要添加: {% csrf_token %}

消除浏览器自带提示:在form内添加 novalidate

html 复制代码
#html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <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>
python 复制代码
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})

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

python 复制代码
def logout(request):
    """注销"""
    request.session.clear()
    return redirect('/login/')
python 复制代码
登录完成,则{{ request.session.info.name }}一定存在,可以直接传到html中
相关推荐
web Rookie9 分钟前
React 中 createContext 和 useContext 的深度应用与优化实战
前端·javascript·react.js
man201713 分钟前
【2024最新】基于Python+Mysql+django的水果销售系统Lw+PPT
数据库·mysql·django
男孩1213 分钟前
react高阶组件及hooks
前端·javascript·react.js
m0_7482517233 分钟前
DataOps驱动数据集成创新:Apache DolphinScheduler & SeaTunnel on Amazon Web Services
前端·apache
珊珊来吃34 分钟前
EXCEL中给某一列数据加上双引号
java·前端·excel
诚威_lol_中大努力中36 分钟前
关于pytorch3d的安装
人工智能·pytorch·python
GISer_Jing42 分钟前
神经网络、深度学习、卷积神经网络
python
onejason1 小时前
深度解析:利用Python爬虫获取亚马逊商品详情
前端·python
胡西风_foxww1 小时前
【ES6复习笔记】Spread 扩展运算符(8)
前端·笔记·es6·扩展·运算符·spread
小王子10241 小时前
数据结构与算法Python版 二叉查找树
数据结构·python·算法·二叉查找树