python之路(20)django之Form组件

前言

  Form组件的几大作用

  • 生成HTML标签
  • 验证用户数据(显示错误信息)
  • HTML Form提交保留上次提交数据
  • 初始化页面显示内容

目录


 Form组件的创建

views

from django.shortcuts import render,HttpResponse,redirect
from django import forms
from django.forms import fields


class F1Form(forms.Form):
    # 不能为空,长度6-18
    user = fields.CharField(
        max_length=18,
        min_length=6,
        required=True,
        #自定义错误的提示
        error_messages={'required': '用户名不能为空','max_length': '太长了','min_length': '太短了','invalid':'..'}
    )
    # 不能为空,长度32
    pwd = fields.CharField(required=True,min_length=32)
    # 不能为空,邮箱格式
    age = fields.IntegerField(
        required=True,
        error_messages={'required':'年龄不能为空', 'invalid':'必须为数字'}
    )
    # 不能为空,数字格式
    email = fields.EmailField(
        required=True,
        min_length=8,
        error_messages={'required':'邮箱不能为空', 'invalid':'邮箱格式错误'}
    )




def f1(request):
    if request.method == "GET":
        obj = F1Form()
        return  render(request,'f1.html',{'obj':obj})
    else:
        # u = request.POST.get('user') #不能为空,长度6-18
        # p = request.POST.get('pwd') #不能为空,长度32
        # e = request.POST.get('email') #不能为空,邮箱格式
        # a = request.POST.get('age') #不能为空,数字格式
        # print(u,p,e,a)

        # 检查是否为空
        # 检查格式是否正确
        obj = F1Form(request.POST)
        # 用户是否验证成功
        if obj.is_valid():
            #用户提交的数据
            print('验证成功',obj.cleaned_data)
            #验证失败返回<ul class="errorlist"><li>user<ul class="errorlist">
            # <li>Ensure this value has at least 6 characters (it has 4).</li></ul></li></ul>
            return redirect('http://www.baidu.com')
        else:
            #显示错误信息
            print('验证失败',obj.errors)
            #验证成功返回字典 {'user': '121212', 'pwd': '11111111111111111111111111111111', 'age': 12, 'email': '11111111@qq.com'}
            return  render(request,'f1.html',{'obj':obj})

        return  HttpResponse('OK')

html

    <form id="fm" action="/f1.html" method="POST" novalidate>
        <!--
        <P><input type="text" name="user"/>{{ obj.errors.user.0 }}</P>
        <P><input type="text" name="pwd"/>{{ obj.errors.pwd.0 }}</P>
        <P><input type="text" name="age"/>{{ obj.errors.age.0 }}</P>
        <P><input type="text" name="email"/>{{ obj.errors.email.0}}</P>
        -->
        <!--
         <p>{{ obj.as_p }}</p> 
        -->
        <p>{{ obj.as_p }}</p>
        <P>{{ obj.user }}{{ obj.errors.user.0 }}</P>
        <P>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</P>
        <P>{{ obj.age }}{{ obj.errors.age.0 }}</P>
        <P>{{ obj.email }}{{ obj.errors.email.0}}</P>
        <input type="submit" value="提交"/>
    </form>

 Form类的内置字段

Fields
        required = True,            #是否必填
        error_messages = {}          #自定义错误提示
        widget = widgets.Select(),   #定制HTML插件
        label = '用户名',            #{{obj.user.label}}
        initial = '请输入默认值',    #添加默认值
        help_text = '帮助文档',
        show_hidden_initial = True,  #是否在当前插件后面在加一个隐藏且具有默认值的插件(可用于检验两次输入是否一致)
        validators = [],             #自定制验证规则
        localize = False,            #是否支持本地化
        disabled = False,            #是否可编辑
        label_suffix = ':',          #后缀


CharField(Fields)
        max_length = None,        #最大长度
        min_length = None,        #最小长度
        strip = True,             #是否移除空白
        error_messages = {'max_length': '太长了', 'min_length': '太短了'},   #自定义错误提示


RegexField(CharField)
        regex,                  #自定制正则表达式
        error_messages=None,   #error_messages={'invalid':'格式错误的字段都是invalid'}


URLField(CharField)
        ...


EmailField(CharField)
        ...
    

SlugField(CharField)      #数字,字母,下划线,减号(连字符)
        ...


UUIDField(CharField)      #uuid类型
        ...


FileField(Field)
        max_length = None,            #设置最大长度
        allow_empty_file = False,    #是否允许为空


ImageField(FileField)
        ...
        注:需要PIL模块,pip3 install Pillow
        以上两个字典使用时,需要注意两点:
            - form表单中 enctype="multipart/form-data"
            - view函数中 obj = MyForm(request.POST, request.FILES)


ChoiceField(Field)
        choices=(),             #选项,如:choices = ((0,'上海'),(1,'北京'),)


ModelChoiceField(ChoiceField)
        ...                        django.forms.models.ModelChoiceField
        queryset,                  # 查询数据库中的数据
        empty_label="---------",  # 默认空显示内容
        to_field_name=None,        # HTML中value的值对应的字段
        limit_choices_to=None      # ModelForm中对queryset二次筛选


FilePathField(ChoiceField)     #文件选项,目录下文件显示在页面中
        path,                      #文件夹路径
        match=None,                #正则匹配
        recursive=False,           #递归下面的文件夹
        allow_files=True,          #允许文件
        allow_folders=False,       #允许文件夹
        required=True,
        widget=None,
        label=None,
        initial=None,
        help_text=''


IntegerField(Fields)
        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 - 0111: 12

DurationField(Field)  #时间间隔: % d % H: % M: % S. % f
        ...

GenericIPAddressField
        protocol = 'both',      #both, ipv4, ipv6支持的IP格式
        unpack_ipv4 = False     #解析ipv4地址,如果是::ffff: 192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用

注:在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。

方式一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields


class MyForm(Form):
    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id', 'caption')  

方法二:

使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现

from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model


class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

Form组件的验证扩展

 方法一:

使用RegexValidator模块

from django.forms import Form
from django.forms import fields
from django.core.validators import RegexValidator


class MyForm(Form):
    user = fields.CharField(
        error_messages={'invalid': '.....'},
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    )

方法二:

使用 RegexField字段

from django.forms import Form
from django.forms import widgets
from django.forms import fields


class MyForm(Form):
    user = fields.RegexField(r'^[0-9]+$',error_messages={'invalid':'.....'})

方法三:

自定义方法,自定义方法 clean_字段名

from django.shortcuts import render
from django import forms
from django.forms import fields
from django.forms import widgets
from app03 import models
# Create your views here.

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError


class MyForm(forms.Form):
    username = fields.CharField()
    user_id = fields.IntegerField(
        widget=widgets.Select(choices=[(0, 'chen'), (1, 'xiaoyi'), (2, 'liu'), ])
    )

    # 自定义方法 clean_字段名
    # 必须返回值self.cleaned_data['username']
    # 如果出错:raise ValidationError('用户名已存在')
    def clean_username(self):
        v = self.cleaned_data['username']
        if models.UserInfo.objects.filter(username=v).count():
            # 自己详细错误信息
            raise ValidationError('用户名已存在')
        return v

    def clean_user_id(self):
        return self.cleaned_data['user_id']

    #整体的错误信息返回
    def clean(self):
        value_dict = self.cleaned_data
        v1 = value_dict.get('username')
        v2 = value_dict.get('user_id')
        if v1 == 'root' and v2 == 1:
            raise ValidationError('整体错误信息')
        return self.cleaned_data 

在源码中会会通过反射去执行clean_"字段名"的方法,再将值赋值给self.cleaned_data[name]

    def _clean_fields(self):
        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.
            if field.disabled:
                value = self.get_initial_for_field(field, name)
            else:
                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:
                    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)
原文地址:https://www.cnblogs.com/shuzhixia/p/11180618.html