【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中
相关推荐
森叶4 分钟前
Electron 主进程中使用Worker来创建不同间隔的定时器实现过程
前端·javascript·electron
霸王蟹13 分钟前
React 19 中的useRef得到了进一步加强。
前端·javascript·笔记·学习·react.js·ts
霸王蟹13 分钟前
React 19版本refs也支持清理函数了。
前端·javascript·笔记·react.js·前端框架·ts
繁依Fanyi18 分钟前
ColorAid —— 一个面向设计师的色盲模拟工具开发记
开发语言·前端·vue.js·编辑器·codebuddy首席试玩官
孙胜完不了24 分钟前
Day29
python
lkx0978824 分钟前
第四天的尝试
python
lcccyyy141 分钟前
day 29
python
明似水1 小时前
Flutter 开发入门:从一个简单的计数器应用开始
前端·javascript·flutter
沐土Arvin1 小时前
前端图片上传组件实战:从动态销毁Input到全屏预览的全功能实现
开发语言·前端·javascript
(・Д・)ノ2 小时前
python打卡day29
开发语言·python