Django中的forms组件实例详解

Form介绍

我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。

与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。

Django form组件就实现了上面所述的功能。

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

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

先在应用目录下my_forms.py定义好一个UserForm类

from django import forms
 from django.forms import widgets
   class UserForm(forms.Form):
     username = forms.CharField(min_length=4, label='用户名',
                   widget=widgets.TextInput(attrs={"class": "form-control"}),
                   error_messages={
                     "required": "用户名不能为空",
                   })
     pwd = forms.CharField(min_length=4, label='密码',
                error_messages={
                  "required": "密码不能为空",
                },
                widget=widgets.PasswordInput(attrs={"class": "form-control"}))
     r_pwd = forms.CharField(min_length=4, label='确认密码',
                 widget=widgets.PasswordInput(attrs={"class": "form-control"}),
                 error_messages={
                   "required": "密码不能为空",
                 })
     email = forms.EmailField(label='邮箱',
                 widget=widgets.EmailInput(attrs={"class": "form-control"}),
                 error_messages={
                   "required": '邮箱不能为空',
                   "invalid": "邮箱格式错误",
                 })
     tel = forms.CharField(label='手机号',
                widget=widgets.TextInput(attrs={"class": "form-control"}),
                )

再写一个视图函数:

在写一个视图函数

   def reg(request):
     form = UserForm()
     if request.method == "POST":
       print(request.POST)
       # 实例化form对象的时候,把post提交过来的数据直接传进去
       form = UserForm(request.POST) # form表单的name属性值应该与forms组件的字段名称一致
       if form.is_valid():
         print(form.cleaned_data)
         return HttpResponse('注册成功')
     return render(request, 'reg.html', locals())

login.html

  <!DOCTYPE html>
   <html lang="zh_CN">
   <head>
     <meta charset="UTF-8">
     <meta http-equiv="x-ua-compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <title>注册</title>
   </head>
   <body>
   <h3>传统form表单</h3>
   <form action="" method="post">
     {% csrf_token %}
     <p>用户名:<input type="text" name="username"></p>
     <p>密码:<input type="password" name="pwd"></p>
     <p>确认密码:<input type="password" name="r_pwd"></p>
     <p>邮箱:<input type="email" name="email"></p>
     <p>手机号:<input type="tel" name="tel"></p>
     <p><input type="submit" value="提交"></p>
   </form>
   <h3>forms组件渲染方式1</h3>
   <form action="" method="post" novalidate>
     {% csrf_token %}
     <p>{{ form.username.label }}:{{ form.username }} <span>{{ form.username.errors.0 }}</span></p>
     <p>密码:{{ form.pwd }}
       <span>{{ form.pwd.errors.0 }}</span></p>
     <p>确认密码:{{ form.r_pwd }}
       <span>{{ form.r_pwd.errors.0 }}</span></p>
     <p>邮箱:{{ form.email }}
       <span>{{ form.email.errors.0 }}</span></p>
     <p>手机号:{{ form.tel }}
       <span>{{ form.tel.errors.0 }}</span></p>
     <p><input type="submit" value="提交"></p>
   </form>
   <h3>forms组件渲染标签方式2</h3>
     <form action="" method="post" novalidate>
       {% csrf_token %}
       {% for field in form %}
         <div class="form-group clearfix">
           <label for="">{{ field.label }}</label>
           {{ field }}
           <span style="color: red" class="pull-right">{{ field.errors.0 }}</span>
           {% if field.name == 'r_pwd' %}
             <span style="color: red" class="pull-right">{{ errors.0 }}</span>
           {% endif %}
         </div>
       {% endfor %}
       <input type="submit" value="注册" class="btn btn-default pull-right">
     </form>
   <h3>forms组件渲染标签方式3  不推荐使用</h3>
   <form action="" method="post">
     {% csrf_token %}
     {{ form.as_p }}
     <input type="submit" value="注册">
   </form>
   </body>
   </html>

看网页效果发现 也验证了form的功能:

• 前端页面是form类的对象生成的                                      -->生成HTML标签功能

• 当用户名和密码输入为空或输错之后 页面都会提示        -->用户提交校验功能

• 当用户输错之后 再次输入 上次的内容还保留在input框   -->保留上次输入内容

Form那些事儿

常用字段与插件

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

initial

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

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

error_messages

重写错误信息。

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

password

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


radioSelect

单radio值为字符串

class LoginForm(forms.Form):
  username = forms.CharField(
    min_length=8,
    label="用户名",
    initial="张三",
    error_messages={
      "required": "不能为空",
      "invalid": "格式错误",
      "min_length": "用户名最短8位"
    }
  )
  pwd = forms.CharField(min_length=6, label="密码")
  gender = forms.fields.ChoiceField(
    choices=((1, "男"), (2, "女"), (3, "保密")),
    label="性别",
    initial=3,
    widget=forms.widgets.RadioSelect()
  )

单选Select

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

方式三:

 def clean(self):
     pwd = self.cleaned_data.get('pwd')
     r_pwd = self.cleaned_data.get('r_pwd')
     print(pwd, r_pwd)
     if pwd and r_pwd:
       if pwd == r_pwd:
         return self.cleaned_data
       raise ValidationError('两次密码不一致')
     else:
       return self.cleaned_data
   def clean_username(self):
     val = self.cleaned_data.get('username')
     user = UserInfo.objects.filter(name=val)
     if not user:
       return val
     else:
       raise ValidationError("用户名已注册")
   def clean_tel(self):
     val = self.cleaned_data.get('tel')
     if len(val) == 11:
       return val
     raise ValidationError('手机号格式错误')

总结:

'''
   局部钩子:
     1、is_valid()
     2、self.errors
     3、self.full_clean()
     4、self._clean_fields() 校验每一个字段
    5、for 循环每一个字段名、验证规则对象
     6、
       验证通过:
         value = field.clean(value)
         self.cleaned_data[name] = value       添加到clean_data中
         利用反射、钩子自定义验证规则
         hasattr(self, 'clean_%s' % name)      写自定义方法
         value = getattr(self, 'clean_%s' % name)() 执行自定义方法
           pass:
             self.cleaned_data[name] = value   添加到clean_data中
           no_pass:
             raise ValidationError(msg)     抛出异常
       不通过:
         raise ValidationError(msg)
   全局钩子:
     1、is_valid()
     2、self.errors
     3、self.full_clean()
     4、self._clean_form()  全部字段调用完成之后 调用
     5、self.clean() 重写clean方法
     6、全局钩子错误:forms.errors.get("__all__")
   '''

总结

以上所述是小编给大家介绍的Django中的forms组件实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Django组件content-type使用方法详解

    前言 一个表和多个表进行关联,但具体随着业务的加深,表不断的增加,关联的数量不断的增加,怎么通过一开始通过表的设计后,不在后期在修改表,彻底的解决这个问题呢呢 django中的一个组件content-type可以帮助我们解决这样的一个问题 在这里我先设计了3张表 学位表 普通课程 和价格策略表 大致的设计如下 在上图中我们可以看到价格策略表和其他的两个表进行了关联,可以根据表明 models.py from django.db import models from django.contrib.

  • 基于Django的ModelForm组件(详解)

    创建类 from django.forms import ModelForm from django.forms import widgets as wd from app01 import models class 类名(ModelForm): class Meta: model = models.表名 #models中的表名 fields="__all__", # 字段 exclude=None, # 排除字段 widgets=None, # 自定义插件 error_message

  • Python的Django中django-userena组件的简单使用教程

    利用twitter/bootstrap,项目的基础模板算是顺利搞定.接下来开始处理用户中心. 用户中心主要包括用户登陆.注册以及头像等个人信息维护.此前,用户的注册管理我一直使用django-registration.只是这个APP有些不思进取,09年发布了0.8alpha版后就一直没什么动静.这次决定尝试另外一个用户模块组件django-userena. 相比django-registration,django-userena的功能要完善的多.除基础的登陆注册模块外django-userena

  • 使用Python的Django框架中的压缩组件Django Compressor

    为了加快网站的加载速度,我们通常要多js和css进行压缩处理.这些js和css的压缩工作如果都手动处理,费时费力. Django Compressor 可以实现js/css的自动压缩.Django Compressor在易用性方面做的非常好,按照 文档 做简单的设置后就可以正常工作.强烈建议大家去将文档完整的看一遍(文档很短). 使用的时候,只需要将css/js放到 compress 标签中 Django Compressor 即可自动进行处理.在debug模式时, Django Compres

  • Django ModelForm组件使用方法详解

    一.创建ModelForm from django.forms import ModelForm from appxx import models from django.forms import widgets as wdt # 因为重名,所以起个别名 #定义一个类,比如BookForm,这个类要继承ModelForm,在这个类中再写一个原类Meta(规定写法,注意首字母是大写的) #在这个原类中,有以下属性(部分): class BookForm(ModelForm): class Meta

  • Django Rest framework认证组件详细用法

    本文详细讲述了DRF认证组件的原理以及用法. 源码剖析 讲解DRF版本的时候我们都知道了,在dispatch方法里执行了initial方法来初始化我们的版本. 而在initial方法里有我们的认证.权限.频率组件,如下图: 我们再点进去认证组件看看: 可以看到,我们的权限组件返回的是request.user,那么这里返回的request是新的还是旧的呢? initial方法是在request重新赋值之后执行的,所以我们这里的request是新的--也就是Request类的实例化对象. 所以,这个

  • Django stark组件使用及原理详解

    stark组件是仿照django的admin模块开发的一套组件,它的作用是在网页上对注册的数据表进行增删改查操作 一.配置 1.创建stark应用,在settings.py中注册stark应用 stark APP专门用于存放自定义组件的核心代码. manage.py@stark_demo > startapp stark 在settings.py文件注册stark: INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth',

  • Django中的forms组件实例详解

    Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确.如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.. Django form组件就实现了上面所述的功能. 总结一下,其实form组件的主要功能如下: 生成页面可用的HTML标签 对用户提交的数据进行校验 保留上次输入内容 先在应用目录下my_for

  • 对Python中TKinter模块中的Label组件实例详解

    Python2.7.4 OS-W7x86 1. 简介 Label用于在指定的窗口中显示文本和图像.最终呈现出的Label是由背景和前景叠加构成的内容. Label组件定义函数:Label(master=None, cnf={}, **kw) 其中,kw参数是用来自定义lable组件的键值对. 2. 背景自定义 背景的话,有三部分构成:内容区+填充区+边框 <1>内容区参数有:width,length用于指定区域大小,如果显示前景内容是文本,则以单个字符大小为单位:如果显示的是图像,则以像素为单

  • django中的ajax组件教程详解

    Ajax(Asynchronous Javascript And XML)翻译成英文就是"异步Javascript和XML".即用Javascript语言与服务器进行异步交互,传输的数据为XML,(现在使用更多的是json数据). 向服务器发送请求的途径 1.浏览器地址栏 http://www.baidu.com 默认是get请求 2.form表单发送请求: GET请求 POST请求 3.a标签 href属性 默认是get请求 4.ajax() Ajax的特点 异步交互:客户端发送一个

  • js中自定义react数据验证组件实例详解

    我们在做前端表单提交时,经常会遇到要对表单中的数据进行校验的问题.如果用户提交的数据不合法,例如格式不正确.非数字类型.超过最大长度.是否必填项.最大值和最小值等等,我们需要在相应的地方给出提示信息.如果用户修正了数据,我们还要将提示信息隐藏起来. 有一些现成的插件可以让你非常方便地实现这一功能,如果你使用的是knockout框架,那么你可以借助于Knockout-Validation这一插件.使用起来很简单,例如我下面的这一段代码: ko.validation.locale('zh-CN');

  • vue实现简单表格组件实例详解

    本来想这一周做一个关于vuex的总结的,但是由于朋友反应说还不知道如何用vue去写一个组件,所以在此写写一篇文章来说明下如何去写vue页面或者组件.vue的核心思想就是组件,什么是组件呢?按照我的理解组件就是装配页面的零件,比如一辆车有大大小小许多零件组成,那么同样的一个页面,也是有许多组件构成的比如说头部组件 按钮组件等等,vue三大核心组件 路由 状态管理,路由控制页面的渲染,页面由组件组成,数据有vuex进行管理和改变.下面我会以一个简单的案例来说 第一步:构建一个简单的vue项目,老规矩

  • vue组件编写之todolist组件实例详解

    我们在topNav这个页面上插入一个todolist子组件 我不知道怎么回事,这里的markdown的代码总是串行..所以代码看得不舒服,见谅啊,我最后会放github的源代码地址. 1. 父组件topNav中注册子组件,引入子组件 <template> <div> <p>下面这一行就是定义的组件名称</p> <todo-list></todo-list> <router-view></router-view>

  • Python:Scrapy框架中Item Pipeline组件使用详解

    Item Pipeline简介 Item管道的主要责任是负责处理有蜘蛛从网页中抽取的Item,他的主要任务是清晰.验证和存储数据. 当页面被蜘蛛解析后,将被发送到Item管道,并经过几个特定的次序处理数据. 每个Item管道的组件都是有一个简单的方法组成的Python类. 他们获取了Item并执行他们的方法,同时他们还需要确定的是是否需要在Item管道中继续执行下一步或是直接丢弃掉不处理. Item管道通常执行的过程有 清理HTML数据 验证解析到的数据(检查Item是否包含必要的字段) 检查是

  • Vue的事件响应式进度条组件实例详解

    写在前面 找了很多vue进度条组件,都不包含拖拽和点击事件,input range倒是原生包含input和change事件,但是直接基于input range做进度条的话,样式部分需要做大量调整和兼容性处理.即使做好了,将来需要修改外观,又是一番折腾. 基于以上两个原因,做了一个可以响应input和change事件(即一个是拖动进度条到某处,一个是在进度条某位置点击使其值变为该位置)的div实现的Vue组件,这样既满足了对进度条事件的需求,也带来了如有需求变动,样式修改很方便的好处. 效果图 以

  • 在 webpack 中使用 ECharts的实例详解

    Webpack 是目前比较流行的模块打包工具,你可以在使用 webpack 的项目中轻松的引入和打包 ECharts,这里假设你已经对 webpack 具有一定的了解并且在自己的项目中使用. npm 安装 ECharts 在 3.1.1 版本之前 ECharts 在 npm 上的 package 是非官方维护的,从 3.1.1 开始由官方 EFE 维护 npm 上 ECharts 和 zrender 的 package. 你可以使用如下命令通过 npm 安装 ECharts npm instal

  • Vuejs 单文件组件实例详解

    在之前的实例中,我们都是通过 Vue.component 或者 components 属性的方式来定义组件,这种方式在很多中小规模的项目中还好,但在复杂的项目中,下面这些缺点就非常明显了: 字符串模板:缺乏高亮,书写麻烦,特别是 HTML 多行的时候,虽然可以将模板写在 html 文件中,但是侵入性太强,不利于组件解耦分离. 不支持CSS:意味着当 HTML 和 JavaScript 组件化时,CSS明显被遗漏了 没有构建步骤:限制只能使用 HTML 和 ES5 JavaScript,而不能使用

随机推荐