forms组件

forms组件


功能:校验数据、渲染标签、展示信息


使用:导入forms模块,编写类继承forms.Form类

	from django import forms
  class MyForm(forms.Form):
    pass

校验:

	1.传入待校验的数据
  	form_obj = MyForm({...})
  2.查看是否符合条件
		form_obj.is_valid()
  3.查看符合条件的数据
  	form_obj.cleaned_data
  4.查看不符合条件的数据及原因
  	form_obj.errors

渲染标签

  	方式1:
      {{ form_obj.as_p }}
      {{ form_obj.as_table }}
      {{ form_obj.as_ul }}
    方式2:
      {{ form_obj.username.label }}
      {{ form_obj.username }}
      {{ form_obj.password.label }}
      {{ form_obj.password }}
    方式3:  # 推荐这种,按照forms的特性多的参数会被忽略
      {% for obj in form_obj %}
      	{{ obj.label }}
        {{ obj }}
      {% endfor %}

展示信息

	1.后端接收待检验的数据生成对象
  	form_obj = MyForm(...)
  2.在前端页面上添加一行代码即可
  	{{ obj.errors.0 }}
  3.自定义展示信息
  	字段参数
    	error_messages = {...}
      label = ''
  ps:form表单标签添加novalidate参数可以让浏览器不做校验

钩子🪝函数

​ 钩子函数的含义就是在程序执行的过程中穿插额外的逻辑

比如校验用户名重复(校验单个字段)、校验密码和确认密码是否一致(校验多个字段)

'''钩子函数是数据经过了字段第一层参数校验之后才会执行'''

局部钩子

校验用户名重复

def clean_name(self):  # 专门用于对name字段添加校验规则的函数名
  name = self.cleaned_data.gat('name')  # 获取用户名
  is_exist = models.数据库.objects.filter(name=name)  # 判断用户名是否存在
  if is_exist:
    self.add_error('name', '用户名已存在')  # 抛出错误提示
  return name  # 不存在正常将name返回出去

全局钩子

校验密码和确认密码是否一致

def clean(self):
  password = self.cleaned_data.get('password')  # 获取密码
  confirm_password = self.cleande_data.get('confirm_password')  # 确认密码
  if  password != comfirm_password:  
    self.add_error('confirm_password', '密码不一致')  # 抛出错误提示

forms组件字段参数

字段参数 作用
min_length 最小长度
max_length 最大长度
label 字段名称
error_messages 错误提示
min_value 最小值
max_value 最大值
initial 默认值
validators 正则校验器

正则校验器

from django.core.validators import RegexValidator
		validators=[
      RegexValidator(r'^[0-9]+$', '请输入数字'),  # 因为经过了参数确认,不需要再额外控制位数
      RegexValidator(r'^159[0-9]+$', '数字必须以159开头')]  # 编写特定的正则

控制标签渲染

widget
🌰:
password = forms.CharField(                          widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
)
模板:
forms.widgets.控制type的类型(attrs=控制各项属性:class id ...)

选择标签内部对应关系

多选择编写对应关系
  	hobby = forms.MultipleChoiceField(
        choices=((1, "于心有愧"), (2, "可一可再"), (3, "岁月如歌"),),
    )
    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        self.fields['hobby'].choices = models.Classes.objects.all().values_list('id','caption')

forms组件字段类型

Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              是否可以编辑
    label_suffix=None            Label内容后缀
 
 
CharField(Field)
    max_length=None,             最大长度
    min_length=None,             最小长度
    strip=True                   是否移除用户输入空白
 
IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值
 
FloatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度
 
BaseTemporalField(Field)
    input_formats=None          时间格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...
 
RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 
EmailField(CharField)      
    ...
 
FileField(Field)
    allow_empty_file=False     是否允许空文件
 
ImageField(FileField)      
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示
 
 
ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值
 
MultipleChoiceField(ChoiceField)
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值
 
ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''
 
GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
 
SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...
 
UUIDField(CharField)           uuid类型

forms组件源码分析

if form_obj.is_valid():  # 找到is_valid源代码,理解为什么我们编写的forms字段可以用is_valid判断
  return HttpResponse("OK")
is_valid源码:
    def is_valid(self):
        """
        Returns True if the form has no errors. Otherwise, False. If errors are
        being ignored, returns False.
        翻译:如果表单没有错误则返回True。否则,假的。如果错误被忽略,则返回False。
        """
        return self.is_bound and not self.errors  #is_bound必须为True和errors必须为False

is_bound源码:
		def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
                 initial=None, error_class=ErrorList, label_suffix=None,
                 empty_permitted=False, field_order=None, use_required_attribute=None, renderer=None):
        self.is_bound = data is not None or files is not None
    		'''我们只用关注is_bound,发现他的True条件为data或者files不为空即可
    		data就是我们传入的数据类型,files是我们传入的文件类型,只要有值,就能满足True的条件'''
        
errors源码:
    @property
    def errors(self):
				'''Returns an ErrorDict for the data provided for the form
        翻译:为表单提供的数据返回一个ErrorDict'''
        if self._errors is None:  # 如果_errors为空
            self.full_clean()  # 
        return self._errors  # 如果不为空,返回_errors


print(form_obj.is_valid, form_obj.is_valid())
<bound method BaseForm.is_valid of <MyForm bound=True, valid=False, fields=(name;phone;password;confirm_password;age;addr;email;file;files;gender;hobby;hobby1;keep;hobby2)>> 
False
 
经过粗浅的源码分析:
		个人理解为,is_valid会根据内容是否为空,和errors信息必须为False,这样就比较好理解了,我们编写的forms代码就会被进行判断,发现错误errors就会对其进行记录,只要errors为空,就证明了接受到的数据都满足了我们的forms要求。至于具体的检验,还需理解

ModelForm简介

​ 我们在编写类的组件的时候,还需要到forms类中重新写一遍;使用ModelForm即可很好的结合forms与models的关系。

class MyUser(forms.ModelForm):
    class Meta:
        model = models.User  # 指定关联的表
        fields = '__all__'  # 所有的字段全部生成对应的forms字段
        labels = {
            'name': '用户名',
            'age': '年龄',
            'addr': '地址',
            'email': '邮箱'
        }
        widgets = {
            "name": forms.widgets.TextInput(attrs={"class": "form-control"}),
        }
        
def reg(request):
    form_obj = MyUser()
    if request.method == 'POST':
        form_obj = MyUser(request.POST)
        if form_obj.is_valid():
            # form_obj.save()  # 新增数据
            edit_obj = models.User.objects.filter(pk=5).first()
            form_obj = MyUser(request.POST, instance=edit_obj)  # 是新增还是保存就取决于有没有instance参数
            form_obj.save()  # 编辑数据
    return render(request, 'reg.html', locals())

cookie与session简介

​ HTTP协议的四大特性: 1.基于请求响应 2.基于TCP/UDP协议之上 3.无状态 4.无/短链接

根据第三条无状态特性,我们可以知道,HTTP协议是无法确认用户情况的,让服务端知道当前用户只有一种情况,携带用户名和密码(身份标识)

cookie🍪:服务端让客户端端保存的数据(存储在客户端上的用户信息数据)

该方法满足了服务端确认用户的的状态,但是问题来了,cookie会将数据明文保存,其安全性就非常的差,session就来了

ession:服务端保存用户数据产生对应的密匙,并告知客户端(存储在服务端的的密匙)

用户登录成功后,如果需要保存cookie,服务端会生成一个随机的字符串,返还给客户端;之后客户端每次发送请求都会携带该随机的字符串;服务端会使用该随机的字符串去做对比,校验有对应关系的用户数据。

1.session的工作必须依赖于cookie

2.客户端也有权拒绝保存数据


django操作cookie

# 视图函数返回值
	return HttpResonse()		
  return render()
  return redirect()
	...
  不直接返回对象 而是先用变量名指代 然后操作对象方法
 	res = HttpResonse()		
  return res
	res = render()
  return res
	res = redirect()
  return res
# 基本使用
	res.set_cookie()  # 设置
  res.COOKIE.get()  # 获取
# 有很多视图函数需要添加登录认证 有时候又需要取消登录认证
	装饰器
# 用户登录之后跳转到用户登录之前想要访问的页面
	提示:利用url问号携带参数 尝试编写  今日作业!!!
posted @ 2022-05-24 01:11  Eason辰  阅读(44)  评论(0)    收藏  举报