Django Form组件

使用Form组件验证

views:

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

# 先定义一个Form类
class LoginForm(forms.Form):
    name = forms.CharField(
        label='用户名',
        initial='陌生人',
        strip=True,
        error_messages={
            'required': '用户名不能为空',
        }
    )

    # 密码框
    password = forms.CharField(
        label='密码',
        min_length=6,
        widget=forms.PasswordInput(render_value=True),
        error_messages={
            'required': '密码不能为空',
            'min_length': '密码不能小于6位',
        }
    )

    # 单选框
    gender = forms.ChoiceField(
        choices=[(1, '男'), (2, '女'), (3, '保密')],
        label='性别',
        initial=3,
        widget=forms.RadioSelect(),
        error_messages={
            'required': '请选择性别'
        }
    )

    # 下拉单选
    hobby = forms.ChoiceField(
        label='爱好',
        widget=forms.Select(),
        choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')),
        initial=2,
    )

    # 多选
    hobby2 = forms.MultipleChoiceField(
        label='爱好2',
        choices=((1, '摩托车'), (2, '汽车'), (3, '游艇')),
        initial=[1, 3],
        widget=forms.SelectMultiple()
    )

    # 单选checkbox
    keep = forms.ChoiceField(
        label='是否记住密码',
        initial='checked',
        widget=forms.CheckboxInput()
    )

    # 多选checkbox
    city = forms.ChoiceField(
        label='居住城市',
        choices=[(1, '北京'), (2, '天津'), (3, '上海'), (4, '武汉')],
        initial=4,
        widget=forms.Select()
    )


# 写一个函数视图
def login(request):
    form_obj = LoginForm()
    if request.method == 'POST':
        form_obj = LoginForm(request.POST)
        if form_obj.is_valid():
            pass

    return render(request, 'app/login.html', {'form_obj': form_obj})

templates:


<form action="/app/login/" method="POST" novalidate>
    {% csrf_token %}
    <p>
        <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label>
        {{ form_obj.name }}
        <span>{{ form_obj.name.errors.0 }}</span>
    </p>
    <p>
        <label for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label>
        {{ form_obj.password }}
        <span>{{ form_obj.password.errors.0 }}</span>
    </p>
    <p>
        <label for="{{ form_obj.gender.id_for_label }}">{{ form_obj.gender.label }}</label>
        {{ form_obj.gender }}
        <span>{{ form_obj.gender.errors.0 }}</span>
    </p>
    <p>
        <label for="{{ form_obj.hobby.id_for_label }}">{{ form_obj.hobby.label }}</label>
        {{ form_obj.hobby }}
        <span>{{ form_obj.hobby.errors.0 }}</span>
    </p>
    <p>
        <label for="{{ form_obj.hobby2.id_for_label }}">{{ form_obj.hobby2.label }}</label>
        {{ form_obj.hobby2 }}
        <span>{{ form_obj.hobby2.errors.0 }}</span>
    </p>
    <p>
        <label for="{{ form_obj.keep.id_for_label }}">{{ form_obj.keep.label }}</label>
        {{ form_obj.keep }}
        <span>{{ form_obj.keep.errors.0 }}</span>
    </p>
    <p>
        <label for="{{ form_obj.city.id_for_label }}">{{ form_obj.city.label }}</label>
        {{ form_obj.city }}
        <span>{{ form_obj.city.errors.0 }}</span>
    </p>

    <p>
        <input type="submit" value="提交">
    </p>
</form>

常用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,              最小值

DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12  

RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}

ChoiceField(Field)
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示

字段校验

RegexValidator验证器
from django.core.validators import RegexValidator
no = forms.CharField(
    label='员工编号',
    validators=[RegexValidator(r'^[0-9]+', '请输入数字'), RegexValidator('^110[0-9]+$', '请以110开头')]
)
自定义函数验证
import re
from django.core.exceptions import ValidationError


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


class LoginForm(forms.Form): 
    mobile = forms.CharField(
        label='手机号',
        validators=[mobile_validate, ],
        error_messages={
            'required': '手机号不能为空',
        }
    )

Hook方法

局部钩子

在Fom类中定义 clean_字段名()方法,就能够实现对特定字段进行校验

class LoginForm(forms.Form):  
    description = forms.CharField(
        label='内容描述',
        initial='暂无描述',
        min_length=4,
        error_messages={
            'required': '不能为空',
            'invalid': '格式错误',
            'min_length': '最少评论4个字'
        }
    )

    def clean_description(self):
        value = self.cleaned_data.get('description')
        if '666' in value:
            raise ValidationError('请不要喊666')
        else:
            return value
全局钩子

在Fom类中定义clean()方法,就能够实现对字段进行全局校验

class LoginForm(forms.Form):
    # 密码框
    password = forms.CharField(
        label='密码',
        min_length=6,
        widget=forms.PasswordInput(),
        error_messages={
            'required': '密码不能为空',
            'min_length': '密码不能小于6位',
        }
    )

    repassword = forms.CharField(
        label='请再次输入密码',
        min_length=6,
        widget=forms.PasswordInput(),
        error_messages={
            'required': '密码不能为空',
            'min_length': '密码不能小于6位',
        }
    )

    def clean(self):
        password_value = self.cleaned_data.get('password')
        repassword_value = self.cleaned_data.get('repassword')
        if password_value == repassword_value:
            return self.cleaned_data
        else:
            self.add_error('repassword', '两次密码不一致')

源码分析

  1. 在执行form_obj.is_valid()进行判断

  2. 进入is_valid方法

    def is_valid(self):
        """
            Returns True if the form has no errors. Otherwise, False. If errors are
            being ignored, returns False.
            """
        return self.is_bound and not self.errors
    

    self.is_bound判断是否有数据

    self.errors判断是否有错误信息

  3. 进入errors属性方法

    @property
    def errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
            return self._errors
    
  4. 进入full_clean方法

    self._errors存放错误信息

    cleaned_data存放验证通过的数据

    def full_clean(self):
        """
            Cleans all of self.data and populates self._errors and
            self.cleaned_data.
            """
        self._errors = ErrorDict()
        if not self.is_bound:  # Stop further processing.
            return
        self.cleaned_data = {}
        # If the form is permitted to be empty, and none of the form data has
        # changed from the initial data, short circuit any validation.
        if self.empty_permitted and not self.has_changed():
            return
    
        self._clean_fields()
        self._clean_form()
        self._post_clean()
    
  5. 执行_clean_fields方法,循环每个字段,分别校验

    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)
    
  6. 执行_clean_form方法

    def _clean_form(self):
        try:
            cleaned_data = self.clean()
        except ValidationError as e:
            self.add_error(None, e)
        else:
            if cleaned_data is not None:
                self.cleaned_data = cleaned_data
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Bootstrap样式来美化Django Form组件。 首先,在Django项目中安装Bootstrap,可以通过pip命令安装: ``` pip install django-bootstrap4 ``` 然后,在Django项目的settings.py文件中添加以下内容: ``` INSTALLED_APPS = [ # ... 'bootstrap4', # ... ] # 设置Bootstrap版本 BOOTSTRAP4 = { 'include_jquery': True, 'jquery_url': '//cdn.bootcss.com/jquery/3.3.1/jquery.min.js', 'base_url': '//cdn.bootcss.com/bootstrap/4.1.3/', } ``` 接着,在Django Form组件中使用Bootstrap样式: ```python from django import forms from django.utils.translation import gettext_lazy as _ class ContactForm(forms.Form): name = forms.CharField( label=_("Your Name"), max_length=100, widget=forms.TextInput(attrs={'class': 'form-control'}), ) email = forms.EmailField( label=_("Your Email"), widget=forms.EmailInput(attrs={'class': 'form-control'}), ) message = forms.CharField( label=_("Message"), widget=forms.Textarea(attrs={'class': 'form-control'}), ) ``` 在这个例子中,我们在每个字段的widget参数中添加了class属性,这个class属性的值为form-control,这样就可以使用Bootstrap样式来美化表单组件。 最后,在HTML模板中使用Bootstrap样式: ```html {% extends "base.html" %} {% block content %} <div class="container"> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit" class="btn btn-primary">Submit</button> </form> </div> {% endblock %} ``` 在这个例子中,我们使用了Bootstrap的container类和btn类来美化HTML模板。然后使用form.as_p来渲染表单组件,这个方法会把每个表单组件渲染成一个p标签,每个p标签中包含一个label标签和一个input标签,这样我们就可以使用Bootstrap样式来美化整个表单了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值