订单交易平台四:登录界面(使用Forms组件解决小bug)

总任务:

  • 使用Forms组件解决用户输入错误、空,并且展示错误信息在输入框的下面
  • 解决用户校验,以及用户提交之后还可以将第一次输入的东西继续展示到页面

1.示例

1.1 先导入forms第三方模块包,并且写入我们前端组要校验的字段

```
from django import forms

class LoginForm(forms.Form):
    role = forms.ChoiceField(
        required=True, # 校验输入是否为空
        label='角色',
        choices=(('2', '客户'), ('1', '管理员')),
        widget=forms.Select(attrs={"class": "form-control"})   # attr这里可以写前端的样式
    )
    # <input type = "text" class ="form-control" placeholder="用户名" name="username" >
    username = forms.CharField(
        required=True,
        label='用户名',
        widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "用户名"})
    )
    password = forms.CharField(
        required=True,
        label='密码',
        widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "密码"})
    )
```

1.2 在views.py函数里面实例化一下此类

```
def login(request):
    if request.method == "GET":
        form = LoginForm()
    return render(request, "login.html", {"form": form})
```
  • 在前端进行渲染,将username文本框进行替换
    img

1.3 is_valid()校验数据

![img](https://img2024.cnblogs.com/blog/3339660/202410/3339660-20241006165535136-587355920.png)

 ```
  # 如果校验不成功,则继续返回给页面原本的数据,如果校验成功,则返回一个校验成功之后数据的字典 
  ```

1.4使用到form组件总结

```
class LoginForm(forms.Form):
    role = forms.ChoiceField(
        required=True,
        choices=(("2", "客户"), ("1", "管理员")),
        widget=forms.Select(attrs={"class": "form-control"})
    )
    username = forms.CharField(
        initial="wupeiqi",
        required=True,
        正则表达式
        widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "用户名"})
    )
    
    # 自定义方法(钩子)
    def clean_username(self):
        raise 异常
		return 123
    
form = LoginForm(initial={"username":"xxx","password":"xx"})


- 生成HTML标签 + 携带数据

  - 保留原来提交的数据,不再担心form表单提交时页面刷新。
  - 显示默认值,做编辑页面显示默认值。

- 数据校验,对用户提交的数据格式校验

  form = LoginForm(data=request.POST)
  if form.is_valid():
      print(form.cleaned_data)
  else:
      print(form.errors)

```

2.优化改进(及所需使用form组件功能)

2.1 前端加入for循环,解决字段过多导致代码冗余

img

# ==================================第一部分==================================

class LoginForm(forms.Form):
  role = forms.ChoiceField(
      required=True,
      label='角色',
      choices=(('2', '客户'), ('1', '管理员')),
      widget=forms.Select(attrs={"class": "form-control"})
  )
  # <input type = "text" class ="form-control" placeholder="用户名" name="username" >
  username = forms.CharField(
      required=True,
      label='用户名',
      widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "用户名"})
  )
  password = forms.CharField(
      required=True,
      label='密码',
      widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "密码"}),
      render_value=True
  )

==================================第二部分==================================
{% for field in form %}
          <div class="form-group">
              <label>{{ field.label }}</label>
              {{ field }}
          </div>
      {% endfor %}

2.2 forms组件类中加入限制字段的数量,以及加入错误提示

img

2.3 form校验的流程

  • 每个字段的内部:required + validators + min_length=6,max_length=10

  • 字段的钩子方法

    def clean_username(self):
        user = self.cleaned_data['username']
        # 校验规则
        # 校验失败
        if len(user) < 3:
            from django.core.exceptions import ValidationError
            raise ValidationError("用户名格式错误")
    	return user
    
    print(form.cleaned_data)
    
  • clean

    def clean(self):
        # 对所有值进行校验
        from django.core.exceptions import ValidationError
        # 1.不返回值,默认 self.cleaned_data
        # 2.返回值,self.cleaned_data=返回的值
        # 3.报错,ValidationError ->  self.add_error(None, e)
    
  • _post_clean

    def _post_clean(self):
        pass
    

2.4 form钩子的实际运用

```
class LoginForm(forms.Form):
  role = forms.ChoiceField(
      required=True,
      label='角色',
      choices=(('2', '客户'), ('1', '管理员')),
      widget=forms.Select(attrs={"class": "form-control"})
  )
  # <input type = "text" class ="form-control" placeholder="用户名" name="username" >
  username = forms.CharField(
      required=True,
      label='用户名',
      widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "用户名"})
  )
  password = forms.CharField(
      required=True,
      label='密码',
      widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "密码"}),
      render_value=True
  )

  def clean_username(self):
      user = self.cleaned_data['username']
      # 校验规则
      # 校验失败
      if len(user) < 3:
          from django.core.exceptions import ValidationError
          raise ValidationError("用户名格式错误")
      return user

  def clean_password(self):
      return md5(self.cleaned_data['password'])

  def clean(self):
      # 对所有值进行校验,无论前面的字段校验成功与否
      user = self.cleaned_data.get('username')
      pwd = self.cleaned_data.get('password')
      if user and pwd:
          pass
      from django.core.exceptions import ValidationError
      # 1.不返回值,默认 self.cleaned_data
      # 2.返回值,self.cleaned_data=返回的值
      # 3.报错,ValidationError ->  self.add_error(None, e)
      # print(self.cleaned_data)
      # raise ValidationError("整xxxxx体错误")

  def _post_clean(self):
      pass
```

2.5 如果想要让错误展示在某个字段的下面(form.add.error)

img

2.6 form校验源码解析

img
img
img
img

2.7 登录界面代码最终版

  • 总共分为3个文件

2.7.1 前端login.html文件

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<style>
        .box {
            width: 450px;
            border: 1px solid #f0f0f0;
            margin-left: auto;
            margin-right: auto;
            margin-top: 100px;

            padding-left: 40px;
            padding-right: 40px;
            padding-bottom: 30px;

            box-shadow: 5px 10px 10px rgb(0 0 0 / 5%);
        }
    </style>
</head>
<body>

<div class="box">
    <h2 style="text-align: center;">用户登录</h2>
    <form method="post">
        {% csrf_token %}

        {% for field in form %}
            <div class="form-group" style="position: relative;margin-bottom: 25px">
                <label>{{ field.label }}</label>
                {{ field }}
                <span style="color: red;position: absolute;">{{ field.errors.0 }}</span>
            </div>
        {% endfor %}

        <button type="submit" class="btn btn-primary">登 录</button>

        <a href='{% url 'sms_login' %}' style="float: right;">短信登录</a>
    </form>
</div>

</body>
</html>

2.7.2 后端account.py文件

# -*- coding utf-8 -*-
import random

from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django_redis import get_redis_connection

from web import models
from utils.encrypt import md5
from utils import tencent
from django import forms

"""
@version : python 3.10
@author : T-mars
@file : xxx.py
@time : 2023-10-28 下午13:20
"""


class LoginForm(forms.Form):
    role = forms.ChoiceField(
        required=True,
        label='角色',
        choices=(('2', '客户'), ('1', '管理员')),
        widget=forms.Select(attrs={"class": "form-control"})
    )
    # <input type = "text" class ="form-control" placeholder="用户名" name="username" >
    username = forms.CharField(
        required=True,
        label='用户名',
        widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "用户名"})
    )
    password = forms.CharField(
        required=True,
        label='密码',
        widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "密码"}),
        # render_value=True
    )

    def clean_username(self):
        user = self.cleaned_data['username']
        # 校验规则
        # 校验失败
        if len(user) < 3:
            from django.core.exceptions import ValidationError
            raise ValidationError("用户名格式错误")
        return user

    def clean_password(self):
        return md5(self.cleaned_data['password'])

    def clean(self):
        # 对所有值进行校验,无论前面的字段校验成功与否
        user = self.cleaned_data.get('username')
        pwd = self.cleaned_data.get('password')
        if user and pwd:
            pass
        from django.core.exceptions import ValidationError
        # 1.不返回值,默认 self.cleaned_data
        # 2.返回值,self.cleaned_data=返回的值
        # 3.报错,ValidationError ->  self.add_error(None, e)
        # print(self.cleaned_data)
        # raise ValidationError("整xxxxx体错误")

    def _post_clean(self):
        pass


class SmsLoginForm(forms.Form):
    role = forms.ChoiceField(
        required=True,
        label='角色',
        choices=(('2', '客户'), ('1', '管理员')),
        widget=forms.Select(attrs={"class": "form-control"})
    )
    # <input type = "text" class ="form-control" placeholder="用户名" name="username" >
    mobile = forms.CharField(
        required=True,
        label='手机号',
        widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "手机号"})
    )
    code = forms.CharField(
        required=True,
        label='短信验证码',
        widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "短信验证码"})
    )


# return render(request, 'login.html')
def login(request):
    if request.method == "GET":
        form = LoginForm()
        return render(request, "login.html", {"form": form})

    # 1.接收并获取数据(数据格式或是否为空验证 - Form组件 & ModelForm组件)
    form = LoginForm(data=request.POST)
    if not form.is_valid():
        return render(request, "login.html", {"form": form})

    # 2.去数据库校验  1管理员  2客户
    data_dict = form.cleaned_data
    role = data_dict.pop('role')
    if role == "1":
        user_object = models.Administrator.objects.filter(active=1).filter(**data_dict).first()
    else:
        user_object = models.Customer.objects.filter(active=1).filter(**data_dict).first()

    # 2.1 校验失败
    if not user_object:
        form.add_error("username", "用户名或密码错误")
        return render(request, "login.html", {'form': form})

    # 2.2 校验成功,用户信息写入session+进入项目后台
    mapping = {"1": "ADMIN", "2": "CUSTOMER"}
    request.session['user_info'] = {'role': mapping[role], 'name': user_object.username, 'id': user_object.id}

    return redirect('/home/')

2.7.3

posted @ 2024-10-06 22:39  tmars  阅读(6)  评论(0编辑  收藏  举报