04: Form 验证用户数据 & 生成html

时间:2022-10-21 08:39:31

目录:Django其他篇

01:Django基础篇

02:Django进阶篇

03:Django数据库操作--->Model

04: Form 验证用户数据 & 生成html

05:ModelForm 数据验证 & 生成html & 数据库操作

06: Django Admin

07: Django 学习补充

目录:

1.1 Form作用 与 基本使用返回顶部

  1、form 作用

      1功能1  验证

      2功能2  生成html标签

      3、功能3: HTML Form提交保留上次提交数据

      4、功能4: 初始化页面显示内容

  2、form使用原则

      1新url方式操作(一定要用form方式生成html,避免提交刷新页面,丢失当前页面中填的值)

      2发Ajax请求时可以不用form生成html标签,仅用form做验证,因为ajax请求本身不刷新页面,不必担心填

           的值会丢失,当然使用form生成html也是可以的

  3、form基本使用:对 login.html提交密码做简单长度验证

from django.shortcuts import render,HttpResponse,redirect
from app01.forms import UserForm def login(request):
if request.method == 'GET':
obj = UserForm()
return render(request,'login.html',{'obj':obj}) elif request.method == 'POST':
obj = UserForm(request.POST)
r1 = obj.is_valid()
if r1:
print(obj.cleaned_data)
else:
print(obj.errors)
return render(request,'login.html',{'obj':obj})

views.py中定义处理函数

from django import forms
from django.forms import fields class UserForm(forms.Form):
#1: 这里的name必须要和input框中name的值
name = fields.CharField(
error_messages={'required':'用户名不能为空'},
) #2: 这里的password必须是input框中name的值
password = fields.CharField(
min_length=6,
max_length=10,
error_messages={'required':'密码不能为空',
'min_length':'密码长度不能小于6',
'max_length':'密码长度不能大于12',
}
)

app01/forms.py中定义字段验证规则

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body> <form method="POST" action="/login/">
<p>用户名:<input name="name" type="text">{{ obj.errors.name.0 }}</p>
<p>密 码:<input name="password" type="text">{{ obj.errors.password.0 }}</p>
<p><input type="submit" value="提交"></p>
</form> </body>
</html>

login.html

  4、生成HTML更简单的三种方法,但是耦合性太强,不好定制(不建议使用)

      1. { obj.as_p }
      2. { obj.as_ul }
      3. { obj.as_table }

1.2 from内置字段fields(数据验证)、内置插件widgets(生成html)返回顶部

########################  1、常用的form内置字段    #########################

#1. Field
required=True, # 是否允许为空
widget=None, # HTML插件
label=None, # 用于生成Label标签或显示内容
initial=None, # 初始值
help_text='', # 帮助信息(在标签旁边显示)
error_messages=None, # 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False, # 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一致)
validators=[], # 自定义验证规则
localize=False, # 是否支持本地化(比如需要本地时间而不是utc时间)
disabled=False, # 是否可以编辑
label_suffix=None # Label内容后缀 #2. CharField(Field)
max_length=None, # 最大长度
min_length=None, # 最小长度
strip=True # 是否移除用户输入空白 #3. EmailField(CharField) # 必须为邮件格式 #4. ChoiceField(Field)
choices=(), # 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, # 是否必填
widget=None, # 插件,默认select插件
label=None, # Label内容
initial=None, # 初始值
help_text='', # 帮助提示 #5. FileField(Field) # 上传文件
allow_empty_file=False # 是否允许空文件 #6. 时间格式化(必须输入下面要求的格式)
DateField(BaseTemporalField) # 格式:2015-09-01
TimeField(BaseTemporalField) # 格式:11:12
DateTimeField(BaseTemporalField) # 格式:2015-09-01 11:12 ######################## 2、不常用的form内置字段 ######################### #7. IntegerField(Field)
max_value=None, # 最大值
min_value=None, # 最小值 #8. RegexField(CharField) # 自定义正则表达式
regex, # 自定制正则表达式
max_length=None, # 最大长度
min_length=None, # 最小长度
error_message=None, # 忽略,错误信息使用 error_messages={'invalid': '...'} #9. max_value=None, # 最大值
min_value=None, # 最小值
max_digits=None, # 总长度
decimal_places=None, # 小数位长度 #10. ImageField(FileField)上传图片
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES) #11. BooleanField(Field) # 必须是布尔值 #12. ComboField(Field) # 使用多个验证(比如:即验证最大长度20,又验证邮箱格式)
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) #13. FilePathField(ChoiceField) # 文件选项,目录下文件显示在页面中
path, # 文件夹路径 #14. GenericIPAddressField
protocol='both', # both,ipv4,ipv6支持的IP格式
unpack_ipv4=False # 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1,
PS:protocol必须为both才能启用 #15. URLField(Field) # 必须是url格式 #16. ModelMultipleChoiceField(ModelChoiceField)

form内置字段(做数据验证)

#########################  1、常用的widgets内置插件    #########################

# TextInput(Input)
# PasswordInput(TextInput)
# EmailInput(TextInput)
# Textarea(Widget)
# FileInput # Select
# SelectMultiple
# RadioSelect
# CheckboxInput
# CheckboxSelectMultiple ######################## 2、不常用的widgets内置插件 ######################### # DateInput(DateTimeBaseInput)
# DateTimeInput(DateTimeBaseInput)
# TimeInput(DateTimeBaseInput) # NumberInput(TextInput)
# URLInput(TextInput) # ClearableFileInput
# MultipleHiddenInput
# SplitDateTimeWidget
# SplitHiddenDateTimeWidget
# SelectDateWidget
# HiddenInput(TextInput)
# NullBooleanSelect

内置插件widgets(生成html)

1.3 Form 验证用户数据 & 生成html 使用演示返回顶部

  1、Form验证数据、生成html

from django.shortcuts import HttpResponse,render
from app01 import models
from app01.forms import FM def login(request):
if request.method == 'GET':
obj = FM() # 初始化操作,将字典中的值显示到页面,作为初始化值
return render(request,'login.html',{'obj':obj}) elif request.method == 'POST':
# 获取用户所有数据
# 每条请求数据的验证
# 成功:获取所有正确信息
# 失败:显示错误信息
obj = FM(request.POST,request.FILES) #将POST中提交的所有数据传给处理类(类中做校验)
data = obj.is_valid() #类中对输入信息校验结果,符合返回True,否则返回False
if data:
# obj.cleaned_data 中获取了用户POST中所有正确信息,格式是字典 print(obj.cleaned_data) # 将获取的正确信息字典传入进去就可以直接创建到数据库中
# models.UserInfo.objects.create(**obj.cleaned_data)
else:
print(obj.errors)
return render(request,'login.html',{'obj':obj}) # 法get请求时给页面初始化值
'''
# 从数据库获取数据,传入给initial的值必须是一个字典,且key必须是页面中的字段
dic= {
'user':'tom',
'pwd':'123',
'email':'tom@qq.com',
'city':2,
'mcity':[1,2]
}
# obj = FM(initial=dic) # 初始化操作,将字典中的值显示到页面,作为初始化值
# 为了使用户以get请求也能看到页面内容,在这里也要传入obj
'''

views.py获取前端数据、返回错误信息

from django import forms            #我们定义的类必须继承forms.Form
from django.forms import widgets #widgets是插件,可以生成input框
from django.forms import fields #字段 class FM(forms.Form):
# 字段本身自己只做验证
user = fields.CharField(
error_messages={'required':'用户名不能为空'},
label="用户名", #在input框前面添加一个提示信息,比如“用户名”
initial='root', #在input框中可以设置一个默认值
)
pwd = fields.CharField(max_length=12,
min_length=6,
error_messages={'required':'密码名不能为空',
'min_length':'密码长度不能小于6',
'max_length':'密码长度不能大于12'
},
widget=widgets.PasswordInput(attrs={'class':'c1'}), #变成密码input框
)
email = fields.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误',},
help_text='必须输入邮箱格式'
) f = fields.FileField()
city = fields.ChoiceField(
choices=[(0,'上海'),(1,'广州'),(2,'北京')]
)
mcity = fields.MultipleChoiceField(
choices=[(0,'上海'),(1,'广州'),(2,'北京')]
)

forms.py写form类定义验证规则

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="/login/" method="POST">
<p>{{ obj.user.label }}: {{ obj.user }} {{ obj.errors.user.0 }}</p>
<p>{{ obj.pwd.label }}{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p>
<p>{{ obj.email }} {{ obj.errors.email.0 }} {{ obj.email.help_text }}</p> <p>{{ obj.f }} {{ obj.errors.f.0 }}</p>
<p>{{ obj.p }} {{ obj.errors.p.0 }}</p>
<p>{{ obj.city }} {{ obj.errors.city.0 }}</p>
<p>{{ obj.mcity }} {{ obj.errors.mcity.0 }}</p> <input type="submit" value="提交">
</form> <!-- 1、obj.errors获取到的就是这样的一端html字符串 -->
<!--
1、 obj.user.label 标签显示内容(如:用户名)
obj.user.label_tag
2、 obj.user 自动生成一个input标签,这种表自动保留上一次提交的数据功能
3、 obj.errors.user.0 获取字段错误信息(提取到user字段)
obj.errors 所有字段错误信息的html字符串
obj.user.errors 错误信息(返回html标签)
<ul class="errorlist"><li>用户名不能为空</li></ul>
4、 obj.email.help_text 获取提示帮助信息(必须输入邮箱格式)
--> <!-- 2、obj.errors获取到的就是这样的一端html字符串 -->
<!--
<ul class="errorlist">
<li>user<ul class="errorlist"><li>用户名不能为空</li></ul></li>
<li>pwd<ul class="errorlist"><li>密码名不能为空</li></ul></li>
</ul>
-->
</body>
</html>

login.html生成html

  2、生成HTML常用语法

      1、 obj.user.label                     标签显示内容(如:用户名)
            obj.user.label_tag

      2、 obj.user                            自动生成一个input标签,这种表自动保留上一次提交的数据功能

      3、 obj.errors.user.0              获取字段错误信息(提取到user字段)
            obj.errors                          所有字段错误信息的html字符串
            obj.user.errors                 错误信息(返回html标签)<ul class="errorlist"><li>用户名不能为空</li></ul>

      4、 obj.email.help_text          获取提示帮助信息(必须输入邮箱格式)

   3、操作form对象、数据验证

      1. obj = FM(request.POST)                  #将POST中提交的所有数据传给处理类(类中做校验)
      2. obj.is_valid()                                  #类中对输入信息校验结果,符合返回True,否则返回False
      3. obj.cleaned_data=obj.clean()           #用户POST中所有正确信息,格式就是字典
                                                               #{'mcity': ['0'], 'user': 'root', 'city': '0', }

      4. obj.errors                                         # 所有错误信息的html字符串(ul li格式)
          obj.errors.get('user')                         # user字段错误信息的html字符串(ul li格式)
          obj.errors.get('user')[0]                    #[0]user字段错误信息的错误信息的字符串

1.4 使用choice字段实现radio,select,checkbox功能返回顶部

# 方法1:
user = fields.CharField(
initial=2,
widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
) # 方法2:
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.RadioSelect
)

1、单radio,值为字符串的两种写法

# 方法1:
user = fields.CharField(
initial=2,
widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
) # 方法2:
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)

2、单select,值为字符串的两种写法

user = fields.MultipleChoiceField(
choices=((1,'上海'),(2,'北京'),),
initial=[1,],
widget=widgets.SelectMultiple
)

3、多选select,值为列表

user = fields.CharField(
widget=widgets.CheckboxInput()
)

4、单checkbox

user = fields.MultipleChoiceField(
initial=[2, ],
choices=((1, '上海'), (2, '北京'),),
widget=widgets.CheckboxSelectMultiple
)

5、多选checkbox,值为列表

1.5 form动态从数据库获取数据添加到select下拉菜单中返回顶部

   1、原理介绍

      #1 由于user_type是类中的静态字段,程序一启动,就将值放到fields字段中了

      #2 所以后面数据库修改后user_type的值还是从fields字段中获取的,必须重启程序才能更新数据到页面

      #3 为了实现不必重启程序,我们必须要重写UserInfoForm类的构造方法(每次实例化类都会执行这个构造方法)

      #4 每次刷新页面就会调用UserInfoForm类的构造方法,在构造方法中定义每次刷新网页时再从数据库取一次值,将值赋值给fields对应字段

   2、实现动态从数据库获取数据添加到select下拉菜单中三种方法

from django.shortcuts import render
from app01 import models def index(request):
from app01.forms import UserInfoForm
obj = UserInfoForm() # 这样就可以实现不必重启服务,数据库更新后前台刷新即可看到新数据
# obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
return render(request,'index.html',{'obj':obj})

views.py 中定义处理函数

from django.db import models
from django.db import models class UserType(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name

models.py中创建usertype表

from django import forms
from django.forms import fields #fields字段专门用于验证
from django.forms import widgets #widgets专门用于生成html标签
from app01 import models class UserInfoForm(forms.Form): # 方法1 和 方法2 需要重写构造方法
user_type1 = fields.ChoiceField(choices=[],widget=widgets.Select)
user_type2 = fields.CharField(widget=widgets.Select(choices=[])) def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields['user_type1'].choices = models.UserType.objects.values_list('id','name')
self.fields['user_type2'].widget.choices= models.UserType.objects.values_list('id','name') # 方法3:
from django.forms.models import ModelChoiceField, ModelMultipleChoiceField
# 1 这种方法不必重写构造方法,页面数据库数据就会更新到页面
# 2 但要使用这种方法在创建表的类时必须定义 def __str__(self)
user_type3 = ModelChoiceField(
empty_label='请选择用户类型', #选择框中的提示信息
queryset=models.UserType.objects.all(),
to_field_name='name', #指定那个字段作为value
)

forms.py生成下拉菜单:三种方法

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>{{ obj.user_type1 }}</p>
<p>{{ obj.user_type2 }}</p>
<p>{{ obj.user_type3 }}</p>
<input type="submit" value="提交">
</body>
</html>

index.html生成html

1.6 form验证规则中的内置钩子返回顶部

  1. from验证经历的顺序(搜索:Form and field validation

      1、拿到字段:用户发送一堆数据,根据form循环,拿到第一个字段

      2、正则匹配:先进行fields默认正则表达式判断,然后进行自定的正则表达式判断(如果有)

      3、字段钩子函数:然后执行字段的钩子函数,接着进行第二个字段,然后是第二个字段钩子函数...

      4、clean钩子函数:字段钩子函数执行完了再执行clean钩子函数进行整体验证

      5、_post_clean:     最后执行_post_clean钩子做其他验证

  2、 form验证的错误信息存放位置

      1、字段钩子错误信息放到对应的字段中 (obj.error中对应的字段字典)

      2、整体错误信息会放到 {"__all__":[],}中等价于{'NON_FIELD_ERRORS':[],} (如:执行clean)

  3、forms.py文件中使用这三种钩子

from django import forms
from django.forms import fields #fields字段专门用于验证
from app01 import models
from django.core.exceptions import ValidationError class RegisterForm(forms.Form):
user = fields.CharField()
email = fields.EmailField()
pwd = fields.EmailField() #1 clean_字段名 是字段钩子(每个字段都有对应的这个钩子):如判断:“用户名已存在”
def clean_user(self):
# self.cleand_data['user']是用户提交的数据'
c = models.User.objects.filter(name=self.cleand_data['user']).count()
if not c:
return self.cleand_data['user'] #必须要有返回值
else:
raise ValidationError('用户名已存在',code='xxx') #2 clean钩子对整体验证:如判断“用户名或密码错误”
def clean(self):
c = models.User.objects.filter(
name=self.cleand_data['user'],
pwd=self.cleand_data['pwd']).count()
if c:
return self.cleand_data #正确的值必须return回去
else:
raise ValidationError('用户名或密码错误') #3 在这里可以做 其他验证
def _post_clean(self):
pass

forms.py文件中使用这三种钩子

1.7 form中自定义验证规则两种方法返回顶部

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator class MyForm(Form):
user = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)

法1:使用RegexValidator模块进行自定义验证

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError # 自定义验证规则
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') class PublishForm(Form):
# 使用自定义验证规则
phone = fields.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))

法2:使用validators字段自己写函数进行验证