django学习之- Form

参考:http://www.cnblogs.com/wupeiqi/articles/6144178.html
FORM中的字段只对post上来的数据进行form验证,
主要涉及:字段 和 插件
字段:对用户请求数据的验证。
插件:用于自动生成html。
- 自定义:
- 创建类
- 定义字段(验证)
- 插件(生成html)
- 初始化操作
实例:通过前端html和后台django,通过from实现一个简单的表单验证及多个功能的展示
前端fm.html代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#功能:实现表单进行数据验证,并在验证未通过情况下,页面不进行刷新,只提示错误#}
<form action="/fm" method="post">
    {% csrf_token %}
{#    以下第一个user.label为FM表单user字段的label值,第二个obj.user为FM表单的user字段,最后的一个是FM表单的error_messages错误提醒#}
    {% csrf_token %}
    <p>
        {{ obj.user.label }}{{ obj.user }}{{ obj.errors.user.0 }}
    </p>
    <p>
        {{ obj.pwd.label }}{{ obj.pwd }}{{obj.errors.pwd.0 }}
    </p>
    <p>
        {{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}
    </p>
    <p>
        {{ obj.f.label }}{{ obj.f }}{{ obj.errors.f.0 }}
    </p>
    <p>
{#        这个提交的是选中的文件的路径#}
        {{ obj.p }}
    </p>
    <p>
{#        choice下拉框选项#}
        {{ obj.cite }}
    </p>
    <p>
{#        单选#}
        {{ obj.cite2 }}
    </p>
    <p>
        {{ obj.mcite }}
    </p>
    <input type="submit" value="提交" />
</form>
</body>
</html>
View Code

  后台代码

from django import forms
from django.forms import fields
# widgets 插件可以定义html的标签和样式,fields表示字段
from django.forms import widgets
class FM(forms.Form):
    # 这里的各个字段,本身自己只做验证
    user = fields.CharField(
        error_messages={'required':'用户名不能为空'}, # 错误提醒
        widget = widgets.Textarea(attrs={'class':'c1','style':'background:#e2e3e4'}), # html标签和样式
        label = '用户名', # 标签
        #initial='admin',  # 定义初始值
        )
    pwd = fields.CharField(
        max_length=12,
        min_length=6,
        error_messages={'required':'密码不能为空','min_length':'密码最小长度6位','max_length':'密码最大长度为12位'},
        widget = widgets.PasswordInput(attrs={'style':'background:#e3e4e5'}),
        label = '密码',
    )
    email = fields.EmailField(
        error_messages={'required':'邮箱不可以为空','invalid':'邮箱格式不正确'},
        label = '邮箱',
    )
    f = fields.FileField(
        label='上传文件'
    )
    # 可以显示指定目录下所有的文件
    p = fields.FilePathField(
        path='d:/'
    )
    # 下拉框
    cite = fields.ChoiceField(
        choices=[(0,'bj'),(1,'sh'),(2,'sz')]
    )
    cite2 = fields.CharField(
    initial=2,
    widget=widgets.RadioSelect(choices=((0,'man'),(1,'girl')))
    )
    # 多选下拉框
    mcite = fields.MultipleChoiceField(
        choices=[(0,'bj'),(1,'sh'),(2,'sz')]
    )

def fm(request):
    # GET将返回表单输入框
    if request.method == 'GET':
        # 从数据库提取数据,为字段生成默认值,注意必须为字典格式,健必须为FM的字段名
        dic = {
            'user':'r1',
            'pwd':'abc',
            'email':'test@test',
            'cite':1,
            'mcite':[1,2],
        }
        obj = FM(initial=dic) # 这里将dic作为参数传入,即可生成默认值
        return render(request,'fm.html',{'obj':obj})
    if request.method == 'POST':
        # POST获取所有提交的数据并进行校验(is_valid),cleaned_data以字典格式返回所有校验成功的数据,errors返回所有校验失败的数据,
        # 直接将obj返回给前端,前端进行错误打印,as_json以json格式打印所有错误
        obj = FM(request.POST)
        ck = obj.is_valid()
        if ck:
            print(obj.cleaned_data)
            # 将表单数据进行数据库添加
            models.UserName.objects.create(**obj.cleaned_data)
            return redirect('/fm')
        else:
            print(obj.errors)
            print(obj.errors.as_json())
            return render(request,'fm.html',{'obj':obj})
View Code
Form内置字段:
### 字符串验证###
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, 小数位长度
### 时间格式验证###3
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
...
### 这个就相当于 CharField + validators ####
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)  # URL的正则表达式
...
BooleanField(Field) # 布尔
...
NullBooleanField(BooleanField)
...
### 比较重要######
ChoiceField(Field) # 单选下拉框
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
MultipleChoiceField(ChoiceField) # 多选下拉框
...

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= '' 空值的默认值



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类型
##### 内置插件 ######
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
每个插件内部都可以使用attr自定制属性
实例:通过表单实现单选
forms.py 内容
from django.forms import widgets,fields
from django import forms
from app01 import models
from django.forms.models import ModelChoiceField,ModelMultipleChoiceField
# ModelChoiceField 单选
# ModelMultipleChoiceField 多选
class UserInfoForm(forms.Form):
    user = fields.CharField(
        required=False,
        widget = widgets.Textarea(attrs={'class':'c1'})
    )
    pwd = fields.CharField(
        max_length=12,
        widget = widgets.PasswordInput(attrs={'class':'c1'})
    )
    user_type = fields.ChoiceField(
        # choices=[(0,'普通用户'),(1,'超级用户')],
        choices=[],
        widget=widgets.Select
    )
    user_type2 = fields.CharField(
        widget=widgets.Select(choices=[])
    )
    user_type3 = ModelChoiceField(
        empty_label='请选择用户类型',
        # 使用此方法虽然不用使用构造方法,但是表需要定制__str__方法
        queryset=models.UserType.objects.all(),
        to_field_name='id'  # 生成select标签内option的value值
    )
    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
        self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')
View Code
views.py内容
def index2(request):
    from app01.forms import UserInfoForm
    obj = UserInfoForm()
    return render(request,'indexform.html',{'obj':obj})
indexform.html内容
<body>
<p>{{ obj.user }}</p>
<p>{{ obj.pwd }}</p>
<p>{{ obj.user_type }}</p>
<p>{{ obj.user_type2 }}</p>
<p>{{ obj.user_type3 }}</p>
</body>

form: 数据验证,经历3个阶段

    - 每一个字段(正则,字段钩子)
- clean
- _post_clean
对于错误信息:整体的错误信息放于__all__内。
实例:数据验证,使用钩子
forms.py内容
# 钩子举例,注册,登录
from django.core.exceptions import ValidationError
class RegisterForm(forms.Form):
    '''字段增加验证方式,首先进行user字段的正则表达式验证,如果通过了。然后进行源码里预留的钩子clean_user验证'''
    user = fields.CharField()
    email = fields.EmailField()

    def clean_user(self):
        '''源码里通过钩子clean+_field,增加正则表达式验证'''
        c = models.User.objects.filter(name=self.cleaned_data['user']).count()
        if not c:
            return self.cleaned_data['user']
        else:
            raise ValidationError('用户名已经存在',code='xxx')
    def clean_email(self):
        pass

class LoginForm(forms.Form):
    user = fields.CharField()
    pwd = fields.CharField(validators=[])  # 这个参数可以自定义正则表达式验证

    def clean_user(self):
        '''第一类钩子字段验证,源码里通过钩子clean+_field,增加正则表达式验证'''
        c = models.User.objects.filter(name=self.cleaned_data['user']).count()
        if not c:
            return self.cleaned_data['user']
        else:
            raise ValidationError('用户名已经存在',code='xxx')
    def clean_pwd(self):
        pass
    def clean(self):
        '''第二类钩子 整体进行验证'''
        self.cleaned_data['user']
        self.cleaned_data['pwd']
        c = models.User.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count()
        if c:
            return self.cleaned_data
        else:
            raise ValidationError('用户名或密码错误')
    def _post_clean(self):
        '''第三类钩子'''
        pass
View Code

views.py 内容

 def register(request):
    from app01.forms import RegisterForm
    obj = RegisterForm(request.POST)
    if obj.is_valid():
        obj.cleaned_data
    else:
        obj.errors
 

























原文地址:https://www.cnblogs.com/zy6103/p/8030376.html