Django's form form components

Django's form form components

Use form component

There are three main components form purposes:

  1. HTML tags generated pages available
  2. To verify the data submitted by users
  3. Keep last Input content

Steps for usage:

  1. In the application to create a file folder, random name, for example myforms.py.

  2. Create a form class that inherits from django.forms.Form:

    from django import forms
    
    class LoginForm(forms.Form):
        # username = request.POST.get('username')
        # if '--' in username:
        #     raise
        # {'username':'xxxx','password':''}
        username = forms.CharField(
            label='用户名:',
            required=True,    # 不能为空,默认可不写
            max_length=7,    # 长度不能超过7个字符
            min_length=2,    # 最短不能低于2个字符
            # initial='张三', #初始值
            widget=forms.TextInput(attrs={'class':'c1','placeholder':'请输入用户名'}),
            error_messages={
                'required':'不能为空',
                'max_length':'太长了,难受!',
                'min_length':'太短了,更难受!',
            },
        )
        password = forms.CharField(
            required=True,
            label='密码:',
            widget=forms.PasswordInput(attrs={'class':'c1','placeholder':'请输入密码'},render_value=True), # render_value=True让密码输入的数据保留
        )
        sex = forms.ChoiceField(
            choices=[(1, '男'),(2, '女')],
            widget=forms.RadioSelect(attrs={'xx':'none'}),
        )
  3. In the instance of this class views object and to the front end html page:

    def login(request):
        if request.method == 'GET':
            form_obj = LoginForm()
    
            return render(request,'login.html', {'form_obj':form_obj})
        else:
            form_obj = LoginForm(request.POST)
            # 准备校验,也就是检查不符合格式的部分,并且保存到列表中,写成伪代码为:
            # form_obj
            # username:alexxxxxx -- form_obj.username.errors.append('太长了!!')
            # username:alexxxxxx -- form_obj.username.errors.append('包含了--!feifa zifu')
            # password  form_obj.password.errors.append('太长了!!')
            print(status)
            return render(request,'login.html', {'form_obj':form_obj})
  4. Check data format:

    form_obj = LoginForm(request.POST)
    status = form_obj.is_valid() # 开始校验,第三步的伪代码Django已经封装好,直接使用即可
    print(status)
    
    return render(request,'login.html', {'form_obj':form_obj})
  5. In the front page can be written such information use the form:

    <form action="" method="post" novalidate>
        {% csrf_token %}
        <div>
            <label for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
            {{ form_obj.username }}
            <span>{{ form_obj.username.errors.0 }}</span>
        </div>
        <div>
            <label for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label>
            {{ form_obj.password }}
            <span>{{ form_obj.password.errors.0 }}</span>
        </div>
        <input type="submit">
    
        <div>
            <label for="{{ form_obj.sex.id_for_label }}">{{ form_obj.sex.label }}</label>
            {{ form_obj.sex }}
       </div>
    </form>

Common Fields

CharField plain text

Do not be lured name, password back, there are a variety of other input box, basically on the basis of this CharField carry out his through the plug-in.

But CharFIield most original use, or used to enter the normal text:

username = forms.CharField(    # 也可写成forms.field.CharField而这等价,后面的字段也一样
    label='用户名:',
    initial="张三"    # 设置默认值
    required=True,    # 不能为空,默认可不写
    max_length=7,    # 长度不能超过7个字符
    min_length=2,    # 最短不能低于2个字符
    # initial='张三', #初始值
    widget=forms.TextInput(attrs={'class':'c1','placeholder':'请输入用户名'}),
    error_messages={
        'required':'不能为空',
        'max_length':'太长了,难受!',
        'min_length':'太短了,更难受!',
    },

Password

form is no password input field, with CharField need to write, set to enter the password in the plugin. Password field and other fields are not the same, when the default front-end input data errors, then click Submit without saving the original data. You can be set render_value=Trueso that the field retains data entered by the user in the front:

password = forms.CharField(
    required=True,
    min_length=6,
    label='密码:',
    widget=forms.PasswordInput(attrs={'class':'c1','placeholder':'请输入密码'},render_value=True), # render_value=True让密码输入的数据保留
)

radioSelect radio

Note that this is not CharField, but ChoiceField:

sex = forms.ChoiceField(
    choices=[(1, '男'),(2, '女')],
    widget=forms.RadioSelect(attrs={'xx':'none'}),
)

Radio Select the drop-down box

Note that using a single box ChoiceField, and the inside of the plug-in is Select, otherwise verification of when it will report Select a valid choicean error.

hobby = forms.ChoiceField(
    choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
    label="爱好",
    initial=3,
    widget=forms.widgets.Select()
)

Select multiple selection dropdown box

Checkbox when using MultipleChoiceField, and the inside of the plug-in using a SelectMultiple, otherwise verification time error.

hobby = forms.MultipleChoiceField(
    choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
    label="爱好",
    initial=[1, 3],
    widget=forms.widgets.SelectMultiple()
)

Radio checkbox

keep = forms.ChoiceField(
    label="是否记住密码",
    initial="checked",
    widget=forms.widgets.CheckboxInput()
)

Multi-select checkbox

hobby = forms.MultipleChoiceField(
    choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
    label="爱好",
    initial=[1, 3],
    widget=forms.widgets.CheckboxSelectMultiple()
)

Time Enter date

You must specify the type, time or can not render to select the input box:

date = forms.DateField(widget=forms.widgets.TextInput(attrs={'type': 'date'}))

Streaming choice field from the database

When using the select tag, choices need to configure the options tend to get from the database. However, if in accordance with the usual static field, write dead, values ​​obtained can not be updated in real time. Then we need to override the constructors choice in order to achieve real-time updates.

A way to look for from the database, as a result of the incoming value 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)   # 注意重写init方法的时候,*args和**kwargs一定要给人家写上,不然会出问题,并且验证总是不能通过,还不显示报错信息
        # self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')

Second method, the option as the model object, the entire Incoming:

If this way, the model table model forget, write NNEWType on the __str__method, which would otherwise be to select a block of a target object.

from django import forms
from django.forms import fields

class FInfo(forms.Form):

    authors = forms.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())  # 多选
    #或者下面这种方式,通过forms里面的models中提供的方法也是一样的。
    authors = forms.models.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())  # 多选
    authors = forms.models.ModelChoiceField(queryset=models.NNewType.objects.all())  # 单选

    #或者
    authors = forms.ModelChoiceField(queryset=models.Publisth.objects.all(),widget=forms.Select()) # 单选
    authors = forms.ModelMultipleChoiceField(
        queryset=models.Author.objects.all(),
        widget = forms.Select(attrs={'class': 'form-control'}
                                     ))

All of the built-in form fields

Note: Some fields are not commonly used because of its properties to ...represent temporarily introduced.

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类型

Data validation

We can field parameter data entered by the user preliminary check. But sometimes, we need more complex calibration mode, you need to customize the validation rules.

Data validation process:

  1. Cycle all their own form class in all fields
  2. For field charfield()afferent instantiation validation rules (including rules validators) for verification, and then the hook partial checksum field. Then the next cycle, i.e. the next check field. After completion, self.cleaned_datawhich have the data for each field
  3. The implementation of a global hook

validators

By checking function created using validators property was introduced in the declaration form field. The basics are as follows:

import re
from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator    # 正则校验器

# 这个函数的作用等价于:RegexValidator(r'^(13[0-9]|15[012356789])[0-9]{8}$', '手机号码格式错误')
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')

class LoginForm(forms.Form):
    # 野蛮校验法:
    # username = request.POST.get('username')
    # if '--' in username:
    #     raise
    # {'username':'xxxx','password':''}
    phone = forms.CharField(
        label='用户名:',
        required=True,    # 不能为空
        min_length=11,    # 最短不能低于11个字符
        max_length=11,
        # 应用validator,注意是个列表
        validators=[mobile_validate, RegexValidator(r'.*--.*', '请输入正确手机号')],
        widget=forms.TextInput(attrs={'class': 'c1', 'placeholder': '请输入手机号'}),
        error_messages={
            'required':'不能为空',
            'max_length':'太长了!',
            'min_length':'太短了!',
        },
    )

Local hooks

Local hooks used to verify a specific field, before validation rules still, provides you with a check function to add some hooks. The basics are as follows:

import re
from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator


class LoginForm(forms.Form):
    username = forms.CharField(
        label='用户名:',
        required=True,
        min_length=2,
        widget=forms.TextInput(attrs={'class':'c1','placeholder':'请输入用户名'}),
        error_messages={
            'required':'不能为空',
            'max_length':'太长了,难受!',
            'min_length':'太短了,更难受!',
        },
    )
    
    def clean_username(self):
        value = self.cleaned_data.get('username')
        print(value,type(value))
        if '666' in value:  # 不能含有666
            raise ValidationError('光喊6是没用的!')
        else:
            return value

Global hook

If we want to check two or more data are related, we need to use the global hook, until other verification operation is completed, data validation.

Fom class we define clean()a method, it is possible to achieve global parity fields. After all verification field, and all of the local hook After execution, to perform this check global hook:

from django.shortcuts import render
import re
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django import forms

def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')

class LoginForm(forms.Form):

    password = forms.CharField(
        required=True,
        label='密码:',
        widget=forms.PasswordInput(attrs={'class': 'c1', 'placeholder': '请输入密码'}, render_value=True), # render_value=True让密码输入的数据保留

    )

    confirm_password = forms.CharField(
        required=True,
        label='确认密码:',
        widget=forms.PasswordInput(attrs={'class': 'c1', 'placeholder': '请输入密码'}, render_value=True), # render_value=True让密码输入的数据保留
    )

    # 全局钩子,用来比较密码与验证秘法是否一致
    def clean(self):
        p1 = self.cleaned_data.get('password')
        p2 = self.cleaned_data.get('confirm_password')
        if p1 == p2:
            return self.cleaned_data

        else:
            # raise ValidationError('两次密码不一致!!!你是熊华吗!!!')    # 全局错误,cleaned_data数据不变
            self.add_error('confirm_password','两次密码不一致,你是彭于晏吗!!!!')    # 指定字段错误,cleaned_data中不再有confirm_password

A brief discussion of errors and cleaned_data

After verification, the data entered by the user will be divided into two parts: in line with the rules and irregularities. After each check, in line with the rules of data will be placed cleaned_data, the irregularities of the data will be placed in errors. Next verification, the verification data only in cleaned_data.

cleaned_data qualified data before completion check step, a dictionary, each key is a field name, data values ​​are acceptable, the user input is traced come. Operating cleaned_data way and also operate the same dictionary (nonsense, people themselves dictionary).

cleaned_data is the class attribute, through self.cleaned_datato find and use.

parity errors unqualified data errors which will be placed, is stored as a dictionary in the form:

{'字段名': ['报错信息'], '__all__': ['全部报错信息']}

Error attribute rule and the local field generated hooks, acquired by capturing ValidationError. After capturing this error, the error will be removed from the field cleaned_data the dictionary, it will be stored into the errors dictionary. User-entered data because irregularities, it will not be saved, an error message is instead provided.

If the hook is the global error, but also thrown ValidationError. If there are no other operations are not removed cleaned_data in the field, but will create a dictionary in errors in __all__keywords, an error message global hook into them. Before throwing an exception, we can call self.add_error method, the error is assigned to a field. Calling this method will be removed from the field cleaned_data and added to the errors dictionary, the value will be given the information. Of course, if there is thrown back ValidationError, then it will add errors in the dictionary __all__keywords into the global error messages. So in a global hook, there is no need in two ways simultaneously.

Comprehensive data validation Case

from django.shortcuts import render
import re
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django import forms

def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')

class LoginForm(forms.Form):
    username = forms.CharField(
        label='用户名:',
        required=True,
        min_length=2,
        # validators=[mobile_validate,],
        widget=forms.TextInput(attrs={'class': 'c1', 'placeholder': '请输入用户名'}),
        error_messages={
            'required':'不能为空',
            'max_length':'太长了,难受!',
            'min_length':'太短了,更难受!',
        },
    )

    password = forms.CharField(
        required=True,
        label='密码:',
        widget=forms.PasswordInput(attrs={'class': 'c1', 'placeholder': '请输入密码'}, render_value=True),    # render_value=True让密码输入的数据保留

    )

    confirm_password = forms.CharField(
        required=True,
        label='确认密码:',
        widget=forms.PasswordInput(attrs={'class': 'c1', 'placeholder': '请输入密码'}, render_value=True),

    )

    # 局部钩子
    def clean_username(self):

        value = self.cleaned_data.get('username')
        print(value,type(value))
        if '666' in value:  # 不能含有666
            raise ValidationError('光喊6是没用的!')
        else:
            return value

    # 全局钩子
    def clean(self):
        p1 = self.cleaned_data.get('password')
        p2 = self.cleaned_data.get('confirm_password')
        if p1 == p2:
            return self.cleaned_data
        else:
            # raise ValidationError('两次密码不一致!!!你是熊华吗!!!')
            self.add_error('confirm_password', '两次密码不一致,你是彭于晏吗!!!!')

HTML wording

form_obj

Form_obj written directly in the template rendering syntax can generate all form labels directly in the form of a table, but because the format is not easy to operate, it is hardly so directly:

{{ form_obj }}

as_p

All input with auto-generated label label label, also the same with the above, is not commonly used. usage:

{{ form_obj.as_p }}

Field name

Generating a field name corresponding to the input tags:

{{ form_obj.字段名 }}

label

Generate a field name tag, which is the field corresponding to the value of the label attribute, if not write label attribute, the default is the field name:

{{ form_obj.字段名.label }}

id_for_label

Input generated ID tag, used to assign the input tag label:

<label for="{{ form_obj.字段名.id_for_label }}">{{ form_obj.字段名.label }}</label>

errors

errors are generated error collection that is essentially the dictionary, but a rewrite __str__method, all errors will appear in the form of an unordered list on the page, but we generally do not print out the error so we generally for each field prints:

{{ form_obj.errors }}    <!-- 输出所有错误出来 -->
{{ form_obj.字段名.errors }}    <!-- 输出指定字段的错误,是个列表 -->
{{ form_obj.字段名.errors.0 }}    <!-- 实际上我们常这样,只拿第一个错误,没必要全拿出来 -->

Integrated use

<div>
    <label for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
    {{ form_obj.username }}
    <span>{{ form_obj.username.errors.0 }}</span>
</div>

Add Batch style (such as Bootstrap style)

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        }

    def __init__(self, *args, **kwargs):
        super(LoginForm, self).__init__(*args, **kwargs)
        for field in iter(self.fields):
            self.fields[field].widget.attrs.update({
                'class': 'form-control',    # Bootstrap 表单样式
            })

Guess you like

Origin www.cnblogs.com/shuoliuchina/p/12521599.html