04- 项目实战-登录页面

一. 登陆

# 1. 需要依赖中间件
# 2. 需要依赖工具类-code.py
# 3. 需要依赖工具类-bootstrap.py
# 4. 需要依赖工具类-md5_data.py

# 5. 将APP中的views.py删除, 创建 views文件夹-->login.py

二. 前置:session和cookie

登陆成功后获取:
    cookie随机字符串
    session用户信息
# 在其他需要登陆才能访问的页面中,都需要加入验证
# 检查用户是否已登陆,已登陆可以继续向下走,未登录,跳转登陆页面
# 用户发来请求,获取cookie随机字符串,拿着随机字符串查看session中有没有
# request.session["info"]  # 不存在会报错

目标: 在所有的视图函数前面统一加上判断(太麻烦,使用中间件解决)
    info = request.session.get("info")
    if not info:
        return redirect("/login/")

可以直接在模板中使用设置的session
       request.session["info"] = {"id": admin_object.id, "name": admin_object.username}  # 会自动生成cookie和在服务器生成session
       request.session.set_expiry(60 * 60 * 24 * 7)  # 设置session时长-7天免登录

       {{ request.session.info.name }}

三. APP-models.py创建管理员表

from django.db import models

class Admin(models.Model):
    """管理员表"""
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)

    # 关联的字段是一个对象,需要加上__str__返回字段
    def __str__(self):
        return self.username

# 执行
python manage.py makemigrations
python manage.py migrate

四. 编写url

from bbc_list.views import login

urlpatterns = [
    path('login/', login.login),  # 登录页的url
    path("image/code/", login.image_code),  # 图片验证码的url

]


五. 编写视图函数(APP-->views-->login.py)

from django import forms
from django.http import HttpResponse
from django.shortcuts import render, redirect
# 使用Form组件
from bbc_list import models
from bbc_list.utils.bootstrap import BootStrapForm
from bbc_list.utils.md5_data import md5
from bbc_list.utils.code import check_code


class LoginForm(BootStrapForm):
    # form需要自定义字段
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput,
        required=True  # required=True: 必填
    )

    password = forms.CharField(label="密码",
                               widget=forms.PasswordInput(render_value=True),  # render_value=True:在输入框保留用户输入的内容
                               required=True)

    code = forms.CharField(label="验证码",
                           widget=forms.TextInput,
                           required=True)

    # 定义一个钩子方法获取密码
    def clean_password(self):
        # # cleaned_data获取用户输入的内容: {'username': '123', 'password': '321'}
        pwd = self.cleaned_data.get("password")
        return md5(pwd)


#  使用modelfprm
# class LoginModelForm(forms.ModelForm):
# modelform需要去数据库里拿数据
#     class Meta:
#         model = models.Admin
#         fields = ["username", "password"]


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():
        # 验证成功,获取到用户名和密码
        # {'username': '123', 'password': '321',"code":"xxx"}
        # print(form.cleaned_data)  # form验证通过后只能form.cleaned_data验证
        user_input_code = form.cleaned_data.pop("code")
        code = request.session.get("img_code", "")
        print("=========", user_input_code, code)
        if code.upper() != user_input_code.upper():
            form.add_error("code", "验证码错误")
            return render(request, "login.html", {"form": form})

        # 去数据库效验用户名和密码是否正确,获取用户对象,如果错的就是None
        # filter(username="form.cleaned_data["username]",password="form.cleaned_data["password]")
        admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
        print("adin_object=", admin_object)
        if not admin_object:
            # form / modelform可以 主动的 手动添加错误信息,(字段名,错误信息)
            form.add_error("password", "用户名或密码错误")
            return render(request, "login.html", {"form": form})

        # 用户名和密码输入正确
        # 网站生成随机字符串,写到用户浏览器的cookie中,在写入到seesion中
        request.session["info"] = {"id": admin_object.id, "name": admin_object.username}  # 会自动生成cookie和在服务器生成session
        request.session.set_expiry(60 * 60 * 24 * 7)  # 7天免登陆

        return redirect("/admin/list/")  # 登陆成功后跳转的页面

    return render(request, "login.html", {"form": form})


from io import BytesIO


def image_code(request):
    """生成验证码图片"""
    # 调用code函数
    img, code_string = check_code()
    # print("img-code=", img, code_string)

    # 写入到session中,以便于后续验证
    request.session["img_code"] = code_string
    # 设置验证码60秒超时
    request.session.set_expiry(60)

    # 创建实力对象
    stream = BytesIO()
    img.save(stream, "png")  # 将图片保存到内存中
    return HttpResponse(stream.getvalue())  # 再从内存获取图片


def logout(request):
    """注销"""
    # 清除当前session
    request.session.clear()

    return redirect("/login/")


六. 编写html(APP-->templates-->login.html)

{% load static %}

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.min.css' %}">
    <style>
        .account{
            width:400px;
            border: 1px solid #dddddd;
            border-radius: 5px;
            box-shadow: 5px 5px 20px #aaa;

            margin-left:auto;
            margin-right:auto;
            margin-top:100px;
            padding:20px 40px;
                    }
        .account h2{
            margin-top:10px;
            text-align:center;
                        }


    </style>

</head>
<body>
<div class="account">
    <h2>用户登陆</h2>
    <form method="post" novalidate>
        {% csrf_token %}
        <div class="form-group">
            <label>用户名</label>
            {{ form.username }}
            <span style="color:red;">{{ form.username.errors.0}}</span>
        </div>

        <div>
            <div class="form-group">
                <label>密码</label>
                {{ form.password }}
                <span style="color:red;">{{ form.password.errors.0}}</span>
            </div>
        </div>

        <div class="form-group">
            <label>图片验证</label>
            <div class="row">
                <div class="col-xs-7">
                    {{ form.code}}
                    <span style="color:red;">{{ form.code.errors.0 }}</span>

                </div>
                <div class="col-xs-5">
                    <img id="image_code" src="/image/code/" style="width:125px;">
                </div>
            </div>
        </div>

        <input type="submit" value="登陆" class="btn btn-primary">

    </form>

</div>
</body>
</html>
posted @ 2023-02-01 11:43  测试圈的彭于晏  阅读(43)  评论(0)    收藏  举报