form组件, ModelForm组件

一:form组件功能
  form 组件:
1.效验
2.页面显示错误信息
3.渲染页面
4.只要错误信息重置

二: form组件的语法:

fm=BookForm({"title":"yuan","price":123,"email":"123"})
fm.is_valid()
# 如果效验失败就返回False
# 如果效验成功就返回True
fm.cleaned_data  返回校成功的数据
{对的数据的键值:对的数据的值}
fm.errors    返回效验错误的数据,后面是列表
{'错的键值':['错误信息',]}
必须先is_valid 才能取出对的和错的数据

注意:

  form表单里的所有字段必须给值,如果不给值就会报错,但是如果给的多就不会报错,

  clean-data里只有效验成功的字段

三.form 组件应用

实例:注册用户

 模型:model.py

class UserInfo(models.Model):
    user=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    email=models.CharField(max_length=32)

 form组件: (写在哪个里都可以)

from django.forms import widgets(需要导入)
class UserForm(forms.Form):
    msg = {"required": '该字段不能为空', "invalid": "格式错误", "min_length": "长度不可以小于五"}  # invalid只适用于邮箱
    # error_messages  自定义错误信息,label  自定义lable显示文字
    user = forms.CharField(min_length=5,
                           error_messages=msg,
                           label='用户名',
                           widget=widgets.TextInput(attrs={"class": "form-control"}))
    pwd = forms.CharField(min_length=5, error_messages=msg, label='密码',
                          widget=widgets.PasswordInput(attrs={"class": "form-control"}))
    r_pwd=forms.CharField(error_messages=msg, label='确认密码',
                          widget=widgets.PasswordInput(attrs={"class": "form-control"}))
    email = forms.EmailField(error_messages=msg, label='邮箱', widget=widgets.EmailInput(attrs={"class": "form-control"}))

 视图函数:

方式一:

 views,py里 

def reg(request):
    if request.method=="GET":
        return render(request,'reg.html')
    if request.method=="POST":
        # 数据校验
        # 直接把它放进来做校验就可以request里多一个crsf-token也没事多余一个也不会报错
        form=UserFrom(request.POST)
        if form.is_valid():
            print(form.cleaned_data)
        else:
            print("来自errorcleaned",form.cleaned_data)
            print("哈哈",form.errors)
            # 因为后面是列表所以需要
            # print('哈哈1',form.errors.get('user')[0])
            error=form.errors
            return render(request,"reg.html",{'error':error})

对应的模板里HTML

 # novalidate   让浏览器对你放行不进行拦截
    <form action="" method="post" novalidate>
        {% csrf_token %}
        <p>用户名<input type="text" name="user"></p><span class="error">{{ error.user.0 }}</span>
        <p>密码<input type="password" name="'pwd"></p><span class="error">{{ error.pwd.0 }}</span>
        <p>邮箱<input type="text" name="email"></p><span class="error">{{ error.email.0 }}</span>
        <p><input type="submit"></p>
    </form>

 方式二:

views.py  

def reg(request):

    if request.method=="POST":
        form = UserFrom(request.POST)
        if form.is_valid():
            print(form.cleaned_data)
        else:
            error = form.errors
            return  render(request,'reg.html',locals())

    form=UserFrom()
    return render(request, "reg.html", locals())

 模板:

# 不能对应加错误
<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}

    <p><input type="submit"></p>
</form>

方式三:

模板:

方式三直接传过来,对的不会重置
<form action="" method="post" novalidate>
    {% csrf_token %}
    <p>用户名{{ form.user }}</p><span class="error">{{ error.user.0 }}</span>
    <p>密码{{ form.pwd }}</p><span class="error">{{ error.pwd.0 }}</span>
    <p>邮箱{{ form.email }}</p><span class="error">{{ error.email.0 }}</span>
    <p><input type="submit"></p>
</form>

 

 方式四:

模板:

{#方式四#}
{#用最后这个就行#}
<form action="" method="post" novalidate>
    {% csrf_token %}

    {% for field in form %}
        <div>
        <lable for=''>{{ field.label }}</lable>
        {{ field }}<span class="error">{{ field.errors.0 }}</span>
        </div>
    {% endfor %}
    <div><input type="submit">提交</div>
</form>

 field就是:{{form.user}}

 

form 组件的使用流程:

源码解析is_valid(self)#self是自定义组件对象

 self._errors = ErrorDict()

如果不加钩子就结束了,如果加钩子继续:

代码:
        form=UserForm(request.POST)
        
        类的实例化:实际上是完成一次赋值,  
            self.field={"user":user,'pwd':pwd,"email":email}
                    后面的值都是类实例化出来的对象,是各自的规则
                     user=forms.CharField(min_length=5,
                         label="用户名",
                         error_messages=msg,
                         widget=widgets.TextInput(attrs={"class":"form-control"})
                         )
                        pwd=forms.CharField(error_messages=msg,
                                               label="密码",
                                              widget=widgets.PasswordInput(attrs={"class":"form-control"})
                                               )
                        email=forms.EmailField(error_messages={"invalid":"邮箱格式错误"},
                                               label="邮箱",
                                               widget=widgets.EmailInput(attrs={"class":"form-control"})
                                               )
                            form.is_valid()
                           
    self._clean_fields() #效验字段                       
    #效验数据
        
        
        def _clean_fields(self):
        
        #field是各自的规则,name是字段字符串
        for name, field in self.fields.items():
            # value_from_datadict() gets the data from the data dictionaries.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            # UserForm({"user":"yuan",'pwd':123,'email':"123"})
            if field.disabled:
                value = self.get_initial_for_field(field, name)
            else:
                # value就是 yuan 等
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.get_initial_for_field(field, name)
                    value = field.clean(value, initial)
                else:
                
                    #field是校验规则,value是  yuan 如果校验不成功直接跳到except里
                    value = field.clean(value)
                self.cleaned_data[name] = value
          # 钩子效验,如果自己的校验规则没通过就不会走钩子
if hasattr(self, 'clean_%s' % name): value = getattr(self, 'clean_%s' % name)()
            # 如果没有直接报错 self.cleaned_data[name]
= value #第一个字段通过第一层校验,然后校验钩子 #(钩子是有顺讯的,第一个拿不到第二个值,后面的可以拿到前面的,因为如果干净就有键值 except ValidationError as e: self.add_error(name, e)
# 定义钩子第一层校验如果失败了,局部的钩子就不执行了
    def clean_user(self):
        val = self.cleaned_data.get('user')
        print(val)
        # user_obj = auth.authenticate(username=val)
        from django.contrib.auth.models import User
        user_obj=User.objects.filter(username=val).first()

        print("haha",user_obj)
        if user_obj:
            raise ValidationError('用户名已存在')

        else:
            return val

    def clean_pwd(self):
        pwd = self.cleaned_data.get('pwd')
        if pwd.isdigit():
            raise ValidationError('密码是纯数字')

        else:
            return pwd

    def clean_email(self):
        import re
        email = self.cleaned_data.get('email')
        if re.search('[0-9a-zA-Z]+@163\.com', email):
            return email
        else:
            raise ValidationError('请输入格式化为@163.com邮箱')
   # 全局勾的错误的键为"__all___"
    def clean(self):
        pwd = self.cleaned_data.get("pwd")
        r_pwd = self.cleaned_data.get("r_pwd")
        print(r_pwd)
        if pwd and r_pwd:
            if pwd == r_pwd:
                return self.cleaned_data
            else:
                raise ValidationError('两次密码不一致!')
        else:
            return self.cleaned_data

 可以给他起个别名,省着显示错误信息得时候还得判断:

def clean(self):
        password =  self.cleaned_data.get('password')
        r_pwd= self.cleaned_data.get('r_pwd')
        print(password,r_pwd)

        if password==r_pwd:
            print('haha')
            return self.cleaned_data
        else:
            self.add_error('r_pwd',ValidationError('密码不一致'))

  

猜你喜欢

转载自www.cnblogs.com/2275114213com/p/9942029.html