Django 组件 Form

Posted 亦非我所愿丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django 组件 Form相关的知识,希望对你有一定的参考价值。

Django Form

Django的Form主要具有一下几大功能:

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

小试牛刀

1、创建Form类

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

class MyForm(Form):
    user = fields.CharField(
        widget = widgets.TextInput(attrs='id': 'i1','classs': 'c1')
    )

    gender = fields.ChoiceField(
        choices = ((1, '男'), (2, '女'),),
        initial = 2,
        widget = widgetss.Radioselect
    )

    city = fieldss.CharField(
        initial = 2,
        widget = widgets.Select(choices=((1, '上海'),(2, '北京'),))
    )

    pwd = fields.CharField(
        widget = widgets.PasswordInput(attrs='class': 'c1', render_value=True)
    )

2、View函数处理

from django.shortcuts import render, redirect
from forms import MyForm
from wanglei import models

def index(request):
    if request.method == 'GET':
        obj = MyForm()
        return render(request, 'index.html', 'obj': obj)
    elif request.method == 'POST':
        obj = MyForm(request.POST, request.FILES)
        if obj.is_valid():
            models.USER.objects.create(**obj.cleaned_data)
            values = obj.clean()
            print(values)
        else:
            errors = obj.errors
            print(errors)
        return render(request, 'index.html', 'form': obj)
    else:
        return redirect('http://www.google.com')

3、生成HTML

<form action="" method="post" enctype="multipart/form-data">
    % csrf_token %
    <p> form.user   form.errors.user.0 </p>
    <p> form.gender   form.gender.errors.0 </p>
    <p> form.city   form.city.errors </p>
    <p> form.pwd   form.pwd.errors </p>
    <input type="submit" />
</form>

其他标签

    <form method="POST" enctype="multipart/form-data">
        % csrf_token %
        
             form.user.label 
             form.user.id_for_label 
             form.user.label_tag 
             form.user.errors 
            <p> form.user   form.user.errors </p>
            <input type="submit" />
    </form>

Form类

创建Form类时,主要涉及到【字段】和【插件】,字段对于用户请求数据的验证,插件用于自动生成HTML

1、Django 内置字段如下

Field          
    required=True,                         # 是否允许为空
    widget=None,                           # HTML插件
    label=None,                            # 用于生成Label标签或显示内容
    initial=None,                          # 初始值
    help_text='',                          # 帮助信息(在标签旁边显示)
    error_messages=None,                   # 错误信息'required': '不能为空', 'invalid': '格式错误'
    show_hidden_initial=False,             # 是否在当前插件后面加一个隐藏的且具有默认值的插件(可用于校验两次输入是否一致) 
    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)               # 格式:2019-01-02
TimeField(BaseTemporalField)               # 格式:11:12
DateTimeField(BaseTemporalField)           # 格式:2019-01-02 11:12

DurationField(Field)                       # 时间间隔

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=(),                            # 选项,如:choice = ((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
    
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val               # 对选中的每一个值进行一次转换
    empty_value = ''                       # 空值的默认值

ComboField(Field)
    fields=()                              
    # 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
    fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])

MultValueField(Field)
    PS:抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultWidget使用

SplitDateTimeField(MultValueField)
    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类型(UUID是根据MAC以及当前时间等创建的不重复的随机字符串)

    ...


Django 内置插件

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultIpleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

常用选择插件

# 单radio,值为字符串
user = fields.CharField(
    initial=2,
    widget=widgets.RadioSelect(choices=((1, '上海'),(2, '北京'),))
)

# 单radio,值为字符串
user = fields.ChoiceField(
    choices=((1, '上海'),(2, ' 北京'),),
    initial=2,
    widget=widgets.RadioSelect
)

# 单select,值为字符串
user = fields.CharField(
    initial=2,
    widget=widgets.Select(choices=((1, '上海'),(2, '北京'),))
)

# 多选select,值为列表
user = fields.MultipleChoiceField(
    choices=((1, '上海'),(2, '北京'),),
    initial=[1, ],
    widget=widgets.SelectMultiple
)

# 单checkbox
user = fields.CharField(
    widget=widgets.CheckboxInput()
)

# 多选checkbox,值为列表
user =fields.MultipleChoiceField(
    initial=[2, ],
    choices=((1, '上海'),(2, '北京'),),
    widget=widgets.CheckboxSelectMultiple
)


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

方式一

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

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
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator

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

自定义验证规则

方式一

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

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

方式二

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError

# 自定义验证规则
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-4]|14[57])[0-8]8$')
    if not mobile_re.match(value)
    raise ValidationError('手机号码格式错误')

class PublishForm(Form):
    title = fields.CharField(
        max_length=20,
        min_length=5,
        error_messages=
            'required': '标题不能为空',
            'min_length': '标题最少为5个字符',
            'max_length': '标题最多为20个字符',
        ,
        widget=widgets.TextInput(attrs='class': 'form-control', 'placeholder': '标题5-20个字符')
        
    phone = fields.CharField(
        validators = [mobile_validate, ],
        error_messages = 'required': '手机不能为空',
        widget  = widgets.TextInput(attrs='class': 'form-control', 'placeholder': u'手机号码')
    )

    email = fields.EmailField(
        required=False,
        error_messages='required': u'邮箱不能为空', 'invalid': u'邮箱格式错误',
        widget=widgets.TextInput(attrs='class': 'form-control', 'placeholder': u'邮箱')
    )
)

方式三:自定义方法

from django import forms
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator

class FInfo(forms.Form):
    username = fields.CharField(
        max_length=5,
        validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')],
        email = fields.EmailField()
        def clean_username(self):
            """
            Form中字段中定义的格式匹配完成后,执行此方法进行验证
            """
            value = self.cleaned_data['username']
            if "666" in value:
                raise ValidationError('666已经被玩烂了...',  'invalid')
            return value
    )

方式四:同时生成多个标签进行验证

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

from django.core.validators import RegexValidator

#####  自定义字段 #####
class PhoneField(fields.MultiValueField):
    def __init__(self, *args, **kwargs):
        # Define one message for all fields.
        error_messages = 
            'incomplete': 'Enter a country calling code and a phone number.'
        
        f = (
             fields.CharField(
                error_messages = 'incomplete': 'Enter a country calling code.',  
                 validators = [RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),],
            ),
             fields.CharField(
                error_messages = 'incomplete': 'Enter  a phone number. ',
                validators = [RegexValidator(r'^[0-9]+$', 'Enter a valid phone number')],
            ),
             fields.CharField(
                 validators = [RegexValidator(r'^[0-9]+$', 'Enter  a valid  extension. ')],
                 required = False,
             ),
        )

        super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args, **kwargs)

    def compress(self, data_list):
        """
        当用户验证都通过后,该值返回给用户
        :param data_list:
        :return:
        """
        return data_list


##### 自定义插件 #####
class SplitPhoneWidget(widgets.MultiWidget):
    def __init__(self):
        ws = (
            widgets.TextInput(),
            widgets.TextInput(),
            widgets.TextInput(),
        )
        super(SplitPhoneWidget, self).__init__(self):
        
    def decompress(self, value):
        """
        处理初始值, 当初始值initial不是列表时,调用该方法
        :param value:
        :return:
        """    
        if value:
            return value.split(',')
        return [None,  None, None]

初始化数据

在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。

1、Form

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validator import RegexValidator

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

2、Views

from django.shortcuts import render, redirect
from forms import MyForm

def index(request):
    if request.method == 'GET':
        values = 'user': 'root', 'city': 2
        obj = MyForm(values)

        return render(request, 'index.html', 'form': obj)
    elif request.method == 'POST':
        return redirect('http://www.google.com')
    else:
        return redirect('http://www.google.com')

3、HTML

<form method='POST' enctype="multipart/form-data">
    % csrf_token %
    <p> form.user   form.user.errors </p>
    <p> form.city   form.city.errors </p>
    <input type="submit" />
</form>

以上是关于Django 组件 Form的主要内容,如果未能解决你的问题,请参考以下文章

Django中form组件的所有内置字段

Python之路71-Django form组件

Form组件

Django之Form组件

Form组件归类

Django之Form组件