forms组件进阶

forms组件钩子函数

钩子函数的作用

用于程序的执行过程中设定额外的逻辑

具体用处

校验用户名是否已存在
钩子函数之局部钩子(校验单个字段)

校验密码和确认密码是否一致
钩子函数之全局钩子(校验多个字段)

# 局部钩子:校验用户名是否已存在(一次性只能设定一个字段)
    注意:钩子函数是数据经过了字段第一层参数校验之后才会执行
def clean_name(self):  # 自动生成的函数名,专门用于对name字段添加额外的校验规则
        # 先获取用户名
        name = self.cleaned_data.get('name')
        # 判断用户名是否已存在
        is_exist = models.User.objects.filter(name=name)
        if is_exist:
            # 提示信息
            self.add_error('name', '用户名已存在')
        # 最后将获取的name返回回去
        return name

# 全局钩子:校验密码与确认密码是否一致(次性只能设定多个字段)
def clean(self):
        # 获取多个字段数据
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not password == confirm_password:
            self.add_error('confirm_password', '两次密码不一致')
        # 最后将整个数据返回
        return self.cleaned_data

forms组件字段参数


forms组件字段类型

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

# regvalidators具体用法
    phone = forms.CharField(label='手机号',
                            validators=[
                                RegexValidator(r'^[0-9]+$', '请输入数字'),
                                RegexValidator(r'0?(13|14|15|17|18|19)[0-9]{9}', '手机号必须位13、14、15、17、18、19开头')],
                            error_messages={
                                'required': '手机号不能为空'
                            },
                            widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
                            )
    
# choices具体用法
选择类型的标签内部对应关系
  	hobby = forms.MultipleChoiceField(
        choices=((1, "游泳"), (2, "跑步"), (3, "睡觉"),(4, "看星星")
    )  # 可直接编写 
    def __init__(self, *args, **kwargs):  # 也可从数据库中获取
        super(MyForm,self).__init__(*args, **kwargs)
        self.fields['hobby'].choices = models.User.objects.all().values_list('id','caption')

forms组件源码分析

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
# 查看类源码发现只要给类传参self.is_bound肯定是True
def is_valid(self):
    return self.is_bound and not self.errors
# 查看类源码发现只有给类传参并且self.errors为False时is_valid的返回值才为True

@property
def errors(self):
   	if self._errors is None:
       self.full_clean()
    return self._errors
# 查看源码发现self._errors初始化就是None,所以肯定会调用full_clean方法

from django.core.exceptions import ValidationError
raise ValidationError('用户名已存在')
# 查看源码发现校验数据的整个过程内部都有异常处理机制

modelform

forms组件主要配合models里面的某些类一起使用,但一些类里面的字段需要在forms类中重写一遍造成代码冗余
为了解决代码冗余产生了ModelForm(基于forms组件)

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()  # 新增数据
    return render(request, 'reg.html', locals())
posted @ 2022-05-23 23:11  一梦便是数千载  阅读(32)  评论(0编辑  收藏  举报