Django之form表单

Posted wjs521

tags:

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

Form介绍

总结,form组件的主要功能如下:

  生成页面可用的html标签

  对用户提交的数据进行校验

  保留上次输入内容

  提示错误信息

普通方式手写注册功能

views.py

def register(request):
    name_error = ‘‘
    if request.method == ‘POST‘:
        user = request.POST.get(‘user‘)
        pwd = request.POST.get(‘pwd‘)
        if len(user) < 6:
            name_error = ‘用户名太短了‘
        else:
            return HttpResponse(‘注册成功‘)
    return render(request, ‘register.html‘, {‘name_error‘: name_error})

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css">
    <link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.css">
    <link rel="stylesheet" href="/static/bootstrap-sweetalert-master/dist/sweetalert.css">
    {% load static %}
    <script src="{% static ‘bootstrap-sweetalert-master/dist/sweetalert.js‘ %}"></script>
    <script src="{% static ‘jquery-3.3.1.min.js‘ %}"></script>
    <script src="{% static ‘bootstrap-3.3.7/js/bootstrap.js‘ %}"></script>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    <p>
        用户名:<input type="text" name="user"><span style="color: red">{{ name_error }}</span>
    </p>
    <p>
        密码:<input type="password" name="pwd">
    </p>
    <button type="submit">提交</button>
</form>
</body>
</html>

使用form组件实现注册功能

views.py

  先定义好一个RegForm类:

from django import forms


# 按照Django form组件的要求自己写一个类
class RegForm(forms.Form):
    user = forms.CharField(label=‘用户名‘)
    pwd = forms.CharField(label=‘密码‘)

  再写一个视图函数:

# 使用form组件实现注册方式
def register2(request):
    form_obj = RegForm()
    if request.method == ‘POST‘:
        # 实例化form对象的时候,把post提交过来的数据直接传进去
        form_obj = RegForm(request.POST)
        # 调用form_obj校验数据的方法
        if form_obj.is_valid():
            return HttpResponse(‘注册成功‘)
    return render(request, ‘register2.html‘, {‘form_obj‘: form_obj})

  进阶版视图函数:

from django import forms
from django.forms import widgets
from app01 import models
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
import re

def check_name(value):
    if ‘alex‘ in value:
        raise ValidationError(‘不符合社会主义核心价值观‘)


# 定义form
class RegForm(forms.Form):
    user = forms.CharField(
        label=‘用户名‘,
        required=False,  # 不允许为空
        min_length=6,  # 最小长度为6
        initial=‘wjs521‘,  # 初识值为wjs521
        disabled=False,  # 不可以编辑
        validators=[check_name],
        error_messages={
            ‘min_length‘: ‘你的长度太短了,还不到6‘,
            ‘required‘: ‘不能为空‘
        }
    )
    #
    pwd = forms.CharField(
        label=‘密码‘,
        min_length=6,
        widget=widgets.PasswordInput()  # HTML插件,页面显示密码时是密文的
    )
    re_pwd = forms.CharField(
        label=‘确认密码‘,
        min_length=6,
        widget=widgets.PasswordInput()
    )

    #
    # gender = forms.ChoiceField(
    #     choices=((1, ‘男‘), (2, ‘女‘), (3, ‘不详‘)),
    #     widget=widgets.CheckboxSelectMultiple()  # 可以进行多选的多选框
    # )
    #
    # hobby = forms.ChoiceField(
    #     # choices=((1, ‘足球‘), (2, ‘篮球‘), (3, ‘双色球‘)),
    #     choices=models.Hobby.objects.all().values_list(‘id‘, ‘name‘),
    #     widget=widgets.SelectMultiple()  # 可以多个选择
    # )

    phone = forms.CharField(
        label=‘手机号‘,
        # validators=[
        #     RegexValidator(r‘^1[3-9]d{9}$‘, ‘手机号不正经‘)
        # ]
    )

    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     self.fields[‘hobby‘].choices = models.Hobby.objects.all().values_list(‘id‘, ‘name‘)

    # def clean_phone(self):
    #     value = self.cleaned_data.get(‘phone‘)
    #     if re.match(r‘^1[3-9]d{9}$‘,value):
    #         return value
    #
    #     raise ValidationError(‘手机号不正经‘)

    # def clean_re_pwd(self):
    #     pwd = self.cleaned_data.get(‘pwd‘)
    #     re_pwd = self.cleaned_data.get(‘re_pwd‘)
    #
    #     if pwd == re_pwd:
    #         return re_pwd
    #     raise ValidationError(‘两次密码不一致‘)

    def clean(self):
        pwd = self.cleaned_data.get(‘pwd‘)
        re_pwd = self.cleaned_data.get(‘re_pwd‘)

        if pwd == re_pwd:
            return self.cleaned_data
        self.add_error(‘re_pwd‘,‘两次密码不一致‘)
        raise ValidationError(‘两次密码不一致‘)
from django.shortcuts import render, HttpResponse
from app01.forms import RegForm


def register(request):
    name_error = ‘‘
    if request.method == ‘POST‘:
        user = request.POST.get(‘user‘)
        pwd = request.POST.get(‘pwd‘)

        if len(user) < 6:
            name_error = ‘你太短了‘

        else:
            # 数据时合格的 进行数据的操作
            return HttpResponse(‘注册成功‘)

    return render(request, ‘register.html‘, {"name_error": name_error})


def register2(request):
    form_obj = RegForm()
    # print(RegForm.hobby.choices)
    # print(11,form_obj.fields[‘hobby‘].choices)

    if request.method == ‘POST‘:
        form_obj = RegForm(request.POST)

        if form_obj.is_valid():
            # cleaned_data  是经过校验的数据
            print(form_obj.cleaned_data)
            # 数据操作
            return HttpResponse(‘注册成功‘)

    return render(request, ‘register2.html‘, {"form_obj": form_obj})

register2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>注册2</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css">
    <link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.css">
    <link rel="stylesheet" href="/static/bootstrap-sweetalert-master/dist/sweetalert.css">
    {% load static %}
    <script src="{% static ‘bootstrap-sweetalert-master/dist/sweetalert.js‘ %}"></script>
    <script src="{% static ‘jquery-3.3.1.min.js‘ %}"></script>
    <script src="{% static ‘bootstrap-3.3.7/js/bootstrap.js‘ %}"></script>
</head>
<body>
{# novalidate 属性是一个布尔属性。 #}
{# novalidate 属性规定当提交表单时不对表单数据(输入)进行验证。 #}

{# input 的属性autocomplete 默认为on #}
{# 其含义代表是否让浏览器自动记录之前输入的值 #}
{# 很多时候,需要对客户的资料进行保密,防止浏览器软件或者恶意插件获取到 #}
{# 可以在input中加入autocomplete="off" 来关闭记录 #}
{# 系统需要保密的情况下可以使用此参数 #}
<form action="" method="post" novalidate autocomplete="off">
    {% csrf_token %}
    {#    {{ form_obj.as_p }} {# 这里是自动生成多个p标签#}
    <p>
        {{ form_obj.user.label }} {# 导入给定的label属性的值 #}
        {{ form_obj.user }} {# 生成某个字段的input框 #}
        <span style="color: red;">{{ form_obj.user.errors.0 }}</span> {# 当做正常的文本内容来展现 #}
        <span style="color: red;">{{ form_obj.user.errors }}</span> {# 不取0的话会当做一个标签展现出来 #}
    </p>
    <p>
        {{ form_obj.pwd.label }}
        {{ form_obj.pwd }} {# 生成某个字段的input框 #}
        <span style="color: red">{{ form_obj.pwd.errors.0 }}</span>
        <span style="color: red">{{ form_obj.pwd.errors }}</span>
    </p>
    <button>注册</button>
</form>
</body>
</html>

常用字段与插件

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

initial

初始值,input框里面的初始值。

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label=‘用户名‘,
        initial=‘wjs‘  # 设置默认值
    )
    pwd = forms.CharField(min_length=6, label=‘密码‘)

error_messages

重写错误信息。

from django import forms


class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label=‘用户名‘,
        error_messages={
            ‘required‘: ‘不能为空‘,
            ‘invalid‘: ‘格式错误‘,
            ‘min_length‘: ‘用户名最短8位‘
        }
    )
    pwd = forms.CharField(min_length=6, label=‘密码‘)

password

from django import forms


class LoginForm(forms.Form):
    pwd = forms.CharField(
        min_length=6,
        label=‘密码‘,
        widget=forms.widgets.PasswordInput(attrs={‘class‘:‘c1‘},
        render_value=True
        )
    )

Radioselect

单radio值为字符串

from django import forms
from django.forms import widgets


class LoginForm(forms.Form):
    gender = forms.fields.ChoiceField(
        choices=((1, ‘男‘), (2, ‘女‘), (3, ‘不详‘)),
        label=‘性别‘,
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

# 单选项

单选Select

from django.forms import widgets


class LoginForm(forms.Form):
    hobby = forms.fields.ChoiceField(
        choices=(
            (1, ‘篮球‘),
            (2, ‘足球‘),
            (3, ‘双色球‘),
        ),
        label=‘爱好‘,
        initial=3,
        widget=forms.widgets.Select()
    )

多选Select

class LoginForm(forms.Form):
    hobby = forms.fields.MultipleChoiceField(
        choices=((1, ‘篮球‘), (2, ‘足球‘), (3, ‘双色球‘)),
            label=‘爱好‘,
            initial=[1,3],
            widget=forms.widgets.SelectMultiple()
    )

单选checkbox

class LoginForm(forms.Form):
    keep = forms.fields.ChoiceField(
        label=‘是否记住密码‘,
        initial=‘checked‘,
        widget=forms.widgets.CheckboxInput()
    )

多选checkbox

class LoginForm(forms.Form):
    hobby = forms.fields.MultipleChoiceField(
        choices=((1, ‘篮球‘), (2, ‘足球‘), (3, ‘双色球‘)),
        label=‘爱好‘,
        initial=[1,3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )  

关于choice的注意事项:

  在使用选择标签时,需要注意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
    )
    
    # 当后台手动的给数据库添加数据时,前台不能的及时获取到新添加的数据,需要重新启动服务器,比较麻烦。所以通过调用父类的__init__()方法——刷新页面时就会获取到新的数据。
    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields[‘user‘].choices = ((1, ‘上海‘), (2, ‘北京‘)),
        # 或
        self.fields[‘user‘].choices = models.Classes.objects.all().values_list(‘id‘,‘caption‘)

方式二:

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


class FInfo(forms.Form):
    # 多选
    authors = form_model.ModelMutipleChoiceField(queryset=models.NNewType.objects.all())
    # 单选
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

Django Form所有内置字段

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

Django Form内置字段  

校验

用自带验证规则:

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

# 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

# ValidationError校验错误 
 
# 自定义验证规则
def mobile_validate(value):
    mobile_re = re.compile(r‘^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{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‘邮箱‘}))

钩子函数

1. 局部钩子

def clean_phone(self):
value = self.cleaned_data.get(‘phone‘)
if re.match(r‘^1[3-9]d{9}$‘,value):
return value

raise ValidationError(‘手机号不正经‘)

2. 全局的钩子

def clean(self):
pwd = self.cleaned_data.get(‘pwd‘)
re_pwd = self.cleaned_data.get(‘re_pwd‘)

if pwd == re_pwd:
return self.cleaned_data
self.add_error(‘re_pwd‘,‘两次密码不一致‘)
raise ValidationError(‘两次密码不一致‘)

 

以上是关于Django之form表单的主要内容,如果未能解决你的问题,请参考以下文章

Django之form表单

django之form表单与ModelForm表单

Django之Form功能

Django之Form表单

Django中Form表单之字段详解

django之form表单验证