Loading

form组件

form组件实现功能:

  • 生成页面可用的HTML标签
  • 对用户提交的数据进行校验,提供错误提示
  • 保留上次输入内容

定义form组件

from django import forms
class RegForm(forms.Form):
    username = forms.CharField(
        label='用户名',
        min_length=6,
        initial='张三',#初始值
        required=True,#必填
        validators=[],#填写校验器
        error_messages={#错误信息
            'required': '用户名是必填项',
            'min_length': '用户名长度不能小于6位'
        }
    )
    #widget生成什么样式的输入框
    pwd = forms.CharField(label='密码', widget=forms.PasswordInput)
    gender = forms.ChoiceField(
        choices=((1, '男'), (2, '女')),
        widget=forms.RadioSelect
    )
    hobby = forms.ModelMultipleChoiceField(
        queryset=models.Hobby.objects.all(),
    )# 数据库变更实时更新

views函数使用form

def reg(request):
    form_obj = RegForm() #实例化一个对象,然后传到模板生成输入框
    if request.method == 'POST':
        form_obj = RegForm(request.POST)  #新建一个带数据的对象覆盖空的
        if form_obj.is_valid():  # 对数据进行校验,然后就有了error信息
            # 在数据库插入数据
            print(form_obj.cleaned_data)  # 通过校验的数据
            return HttpResponse('注册成功')

    return render(request, 'reg.html', {'form_obj': form_obj})

模板使用form

<form action="" method="post" novalidate> <!-- novalidate取消前端校验 -->
    {% csrf_token %}
    <p>
        <label for="{{ form_obj.username.id_for_label }}">
            {{ form_obj.username.label }}
        </label>
        {{ form_obj.username }}
        {{ form_obj.username.errors.0 }}
    </p>

    <p>
        <label for="{{ form_obj.pwd.id_for_label }}">
            {{ form_obj.pwd.label }}
        </label>
        {{ form_obj.pwd }}
        {{ form_obj.pwd.errors.0 }}
    </p>

    <p>
        <label for="{{ form_obj.re_pwd.id_for_label }}">
            {{ form_obj.re_pwd.label }}
        </label>
        {{ form_obj.re_pwd }}
        {{ form_obj.re_pwd.errors.0 }}
    </p>

form对象前端应用

{{ form_obj.as_p }}     ——》  生成一个个P标签 包含着 input  label
{{ form_obj.errors }}    ——》   form表单中所有字段的错误ui-li格式
{{ form_obj.username }}     ——》 一个字段对应的input框
{{ form_obj.username.label }}    ——》  该字段的提示
{{ form_obj.username.id_for_label }}    ——》 该字段input框的id
{{ form_obj.username.errors }}   ——》 该字段的所有的错误
{{ form_obj.username.errors.0 }}   ——》 该字段的第一个错误,字符串格式

常用字段

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                   是否移除用户输入空白
    
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二次筛选

字段参数

required=True,               是否允许为空
widget=None,                 HTML插件
min_length=8
max_length=16
label=None,                  用于生成Label标签或显示内容
initial=None,                初始值
error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
validators=[],               自定义验证规则
disabled=False,              是否可以编辑

常用插件

#CharField
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
#ChoiceField
widget=forms.widgets.RadioSelect()#单radio值为字符串
widget=forms.widgets.Select() #单选Select
widget=forms.widgets.CheckboxInput()#单选checkbox
# MultipleChoiceField
widget=forms.widgets.CheckboxSelectMultiple()#多选checkbox
widget=forms.widgets.SelectMultiple #()多选Select

关于choice的注意事项:

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

方式一:

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

class MyForm(Form):
    hobby = forms.ChoiceField(
            choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
            widget=forms.widgets.SelectMultiple
            # choices=models.Hobby.objects.values_list('id', 'name'),
        	#静态字段只加载一次
        )
 
    def __init__(self, *args, **kwargs):
        super(RegForm, self).__init__(*args, **kwargs)
        self.fields['hobby'].choices = models.Hobby.objects.values_list('id', 'name')
        					

方式二:

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

 
class MyForm(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.Hobby.objects.all())  # 多选
    # authors = form_model.ModelChoiceField(queryset=models.Hobby.objects.all())  # 单选

校验

1.内置校验

required=True
min_length
max_length
。。。

2.自定义校验器

1.自定义校验函数

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-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'邮箱'}))

2.使用内置的校验器

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开头')],
    )

3.钩子函数:

  1. 局部钩子

    def clean_username(self):
        # 局部钩子
        # 通过校验规则  必须返回当前字段的值
        # 不通过校验规则   抛出异常
        v = self.cleaned_data.get('username')
        if 'sb' in v:
            raise ValidationError('敏感词汇')
            else:
                return v
    
  2. 全局钩子

    def clean(self):
        # 全局钩子
        # 通过校验规则  必须返回当前所有字段的值
        # 不通过校验规则   抛出异常   '__all__'
        pwd = self.cleaned_data.get('pwd')
        re_pwd = self.cleaned_data.get('re_pwd')
    
        if pwd == re_pwd:
            return self.cleaned_data
        else:
            self.add_error('re_pwd','两次密码不一致!!!!!')
            raise ValidationError('两次密码不一致')
    

is_valid的流程:

1.执行full_clean()的方法:

定义错误字典

定义存放清洗数据的字典

2.执行_clean_fields方法:

​ 循环所有的字段

​ 获取当前的值

​ 对进行校验 ( 内置校验规则 自定义校验器)

  • 通过校验

    self.cleaned_data[name] = value

    如果有局部钩子,执行进行校验:

    通过校验——》 self.cleaned_data[name] = value

    不通过校验——》 self._errors 添加当前字段的错误 并且 self.cleaned_data中当前字段的值删除掉

  • 没有通过校验

    self._errors 添加当前字段的错误

3.执行全局钩子clean方法

ModelForm

orm与model的终极结合。

class BookForm(forms.ModelForm):

    class Meta:
        model = models.Book
        fields = "__all__"
        labels = {
            "title": "书名",
            "price": "价格"
        }
        widgets = {
            "password": forms.widgets.PasswordInput(attrs={"class": "c1"}),
        }

class Meta:下常用参数:

model = models.Student  # 对应的Model中的类
fields = "__all__"  # 字段,如果是__all__,就是表示列出所有的字段
exclude = None  # 排除的字段
labels = None  # 提示信息
help_texts = None  # 帮助提示信息
widgets = None  # 自定义插件
error_messages = None  # 自定义错误信息

注册示例

from crm import models
from django import forms
from django.core.exceptions import ValidationError
import hashlib

class RegForm(forms.ModelForm):
    #需对密码进行加密,重写ModelForm字段
    password = forms.CharField(min_length=6,
                               widget=forms.PasswordInput(attrs={'placeholder': '您的密码', 'autocomplete': 'off'}))
    re_password = forms.CharField(min_length=6,
                                  widget=forms.PasswordInput(attrs={'placeholder': '您的确认密码', 'autocomplete': 'off'}))

    class Meta:
        model = models.UserProfile
        fields = '__all__'  # ['username']
        exclude = ['is_active']
        widgets = {
            'username': forms.EmailInput(attrs={'placeholder': '您的用户名', 'autocomplete': 'off',}),
            # 'password':forms.PasswordInput(attrs={'placeholder':'您的密码','autocomplete':'off'}),
            'mobile': forms.TextInput(attrs={'placeholder': '您的手机号', 'autocomplete': 'off'}),
            'name': forms.TextInput(attrs={'placeholder': '您的真实姓名', 'autocomplete': 'off'})
        }
        error_messages = {
            'username': {
                'required': '必填',
                'invalid': '邮箱格式不正确'
            }
        }

    def clean(self):
        password = self.cleaned_data.get('password')
        re_password = self.cleaned_data.get('re_password')
        if password == re_password:
            # 对密码进行加密
            md5 = hashlib.md5()
            md5.update(password.encode('utf-8'))
            self.cleaned_data['password'] = md5.hexdigest()
            return self.cleaned_data
        else:
            self.add_error('re_password', '两次密码不一致')
            raise ValidationError('两次密码不一致!!')

应用

def reg(request):
    form_obj = RegForm()
    if request.method == 'POST':
        form_obj = RegForm(request.POST)
        # 对提交的数据进行校验
        if form_obj.is_valid():
            # 校验成功  把数据插入数据中
            # models.UserProfile.objects.create(**form_obj.cleaned_data)
            form_obj.save() #这一步直接写入数据库
            return redirect(reverse('login'))
        print(form_obj.errors)
    return render(request, 'reg.html', {'form_obj': form_obj})

更多参考

进阶参考

posted @ 2019-09-03 19:33  陌路麒麟  阅读(124)  评论(0编辑  收藏  举报