亲宝软件园·资讯

展开

Python Web框架之Django框架Form组件用法详解

人气:0

本文实例讲述了Python Web框架之Django框架Form组件用法。分享给大家供大家参考,具体如下:

Form简介

在HTTP中,表单(form标签),是用来提交数据的,其action属性说明了其传输数据的方法:如何传、如何接收。

访问网站时,表单可以实现客户端与服务器之间的通信。例如查询,就用到了表单(其属性中,action=get)。

再比如说注册与登陆,也是要用到表单的。但这里由于涉及到隐私问题,需要保证数据传输的安全性,因此其传输方法就应当使用post而非get。

总之,对客户端来说,表单就是用来向服务器提交数据的;

而对服务器来说,表单就是你提供给客户端的发送信息的渠道,你需要对用户发送来的信息进行处理和响应,以达到页面的交互。

Django Form的功能

Django Form验证流程

用于验证用户请求数据合法性的一个组件
如果没有Form就得繁琐地用正则表达式了

a. 用户提交数据的验证
  1、创建模版            class LoginForm(forms.Form):...
  2、将请求交给模版,创建一个对象 obj = LoginForm(request.POST)
  3、进行验证           obj.is_valid()
  4、获取正确信息          obj.clean()
  5、获取错误信息          obj.errors
b. 错误信息提示
  Form提交,刷新页面的特性,模版对象内部值丰富,再显示时,值和错误信息都有
c. 保留上一次提交的数据
  1、自动生成html标签
  2、保留上一次提交的数据

Form的创建

from django.shortcuts import render, redirect
from django import forms
#这里为了简单,把form类写到视图函数
# 模版
class LoginForm(forms.Form):
  # 模版中的元素
  user = forms.CharField(min_length=6,error_messages={"required": '用户名不能为空','min_length': '用户名长度不能小6'})
  email = forms.EmailField(error_messages={"required": '邮箱不能为空','invalid': '邮箱格式错误'})
def login(request):
  if request.method == "GET":
    # 数据库中获取
    obj = LoginForm()
    return render(request,'login.html',{'oo': obj})
  elif request.method == "POST":
    """
    obj = LoginForm(request.POST)
    # 验证
    status = obj.is_valid() 
    print(status)
    value_dict = obj.clean() 验证成功的值,输入格式正确的拿到了
    print(value_dict)
    # error_obj = obj.errors
    error_obj = obj.errors.as_json() 
    print(error_obj) code定义错误信息
    """
    obj = LoginForm(request.POST)
    if obj.is_valid():
      value_dict = obj.clean()
      print(value_dict)
      # create(**value_dict)
    else:
      # 封装了所有的错误信息
      # error_obj=obj.errors
      # print(obj.errors['email'][0],type(error_obj['email'])
      # print(obj.errors['email'][0],type(error_obj['email'][0])
      # print(obj.errors["user"][0])
      # print(type(error_obj))
      from django.forms.utils import ErrorDict
      pass
    return render(request, 'login.html',{'oo': obj})

当然你也可以在app里创建form.py文件,在里面创建类:

下文将使用这个文件。

from django import forms as DForms
from django.forms import fields
from django.forms import widgets
from django.core.validators import RegexValidator
class DetailForm(DForms.Form):
  user1 = fields.CharField() #默认input框,可以改成select,radio等
  user2 = fields.CharField(widget=widgets.TextInput)
  user4 = fields.IntegerField()
  # 字符串
  user3 = fields.ChoiceField(choices=[(1, 'SH'), (2, 'BJ'), ])
  user5 = fields.CharField(
    widget=widgets.Select(choices=[(1, 'SH'), (2, 'BJ'), ])
  )
  user6 = fields.IntegerField(
    widget=widgets.Select(choices=[(1, 'SH'), (2, 'BJ'), ])
  )
  user7 = fields.IntegerField(
    widget=widgets.RadioSelect(choices=[(1, 'SH'), (2, 'BJ'), ])
  )
  #{'user1': '11', 'user2': '22', 'user4': 33, 'user3': '1', 'user5': '2', 'user6': 1, 'user7': 2}

视图函数:

from django.shortcuts import render, redirect
from app01 import forms
def detail(request):
  obj = forms.DetailForm(request.POST)
  obj.is_valid()
  print(obj.clean())
  return render(request,'detail.html', {'obj': obj})

生成HTML:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <form action="/detail.html" method="POST">
  {{ obj.user1 }}
  {{ obj.user2 }}
  {{ obj.user3 }}
  {{ obj.user4 }}
  {{ obj.user5 }}
  {{ obj.user6 }}
  {{ obj.user7 }}
    <input type="submit" value="提交"/>
  </form>
</body>
</html>

常用HTML标签:

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
      {{ form.xxoo.label }}
      {{ form.xxoo.id_for_label }}
      {{ form.xxoo.label_tag }}
      {{ form.xxoo.errors }}
      <p>{{ form.user }} {{ form.user.errors }}</p>
      <input type="submit" />
</form>

运行后后台返回结果:

#{'user1': '11', 'user2': '22', 'user4': 33, 'user3': '1', 'user5': '2', 'user6': 1, 'user7': 2}

下面将讲解为什么是这个结果

Django的Form的实现步骤:

a. 创建一个验证用户请求的模板包含:

类:模版,到底验证几个
字段:用于验证用户某个字段
插件:user = forms.CharField(..,widget=Input框)

Django内置字段如下:

1,字段核心参数

每个字段类的构造函数至少接受这些参数。有些字段类接受额外的、字段特有的参数,但以下参数应该总是能接受:

Field.required
默认情况下,每个字段 类都假设必需有值,所以如果你传递一个空的值 —— 不管是None 还是空字符串(“”) —— clean() 将引发一个ValidationError 异常。

Field.label
正如在前面“输出表单为HTML”中解释的,字段默认label 是通过将字段名中所有的下划线转换成空格并大写第一个字母生成的。如果默认的标签不合适,可以指定label。

Field.label_suffix
label_suffix 参数让你基于每个字段覆盖表单的label_suffix。

Field.initial
initial 参数让你指定渲染未绑定的表单中的字段时使用的初始值。

Field.widget
widget 参数让你指定渲染表单时使用的Widget 类。更多信息参见Widgets。

Field.help_text
help_text 参数让你指定字段的描述文本。如果提供help_text,在通过表单的便捷方法(例如,as_ul())渲染字段时,它将紧接着字段显示。

Field.error_messages
error_messages 参数让你覆盖字段引发的异常中的默认信息。传递的是一个字典,其键为你想覆盖的错误信息。

Field.validators
validators 参数让你可以为字段提供一个验证函数的列表。

Field.localize
localize 参数启用表单数据的本地化,包括输入和输出。

Field.has_changed()
has_changed() 方法用于决定字段的值是否从初始值发生了改变。返回True 或False。

2,内建字段

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

  可选参数:max_length, min_length

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
MultipleChoiceField(**kwargs)

TypedMultipleChoiceField(**kwargs)
就像MultipleChoiceField,除了TypedMultipleChoiceField需要两个额外的参数,coerce和empty_value。

TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值

ImageField(**kwargs)

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=''

FileField(**kwargs)

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

3.处理关系字段

两个字段可用于表示模型之间的关系:ModelChoiceField和ModelMultipleChoiceField。这两个字段都需要单个queryset参数,用于创建字段的选择。在表单验证时,这些字段将把一个模型对象(在ModelChoiceField的情况下)或多个模型对象(在ModelMultipleChoiceField的情况下)放置到cleaned_data表单的字典。

对于更复杂的用法,可以在声明表单字段时指定queryset=None,然后在窗体的init()方法中填充queryset:

ModelChoiceField(**kwargs)

ModelMultipleChoiceField(**kwargs)

Django内置插件:

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

# 单radio,值为字符串
# user = fields.CharField(
#   initial=2,
#   widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
# 单radio,值为字符串
# user = fields.ChoiceField(
#   choices=((1, '上海'), (2, '北京'),),
#   initial=2,
#   widget=widgets.RadioSelect
# )
# 单select,值为字符串
# user = fields.CharField(
#   initial=2,
#   widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
# 单select,值为字符串
# user = fields.ChoiceField(
#   choices=((1, '上海'), (2, '北京'),),
#   initial=2,
#   widget=widgets.Select
# )
# 多选select,值为列表
# user = fields.MultipleChoiceField(
#   choices=((1,'上海'),(2,'北京'),),
#   initial=[1,],
#   widget=widgets.SelectMultiple
# )
# 单checkbox
# user = fields.CharField(
#   widget=widgets.CheckboxInput()
# )
# 多选checkbox,值为列表
# user = fields.MultipleChoiceField(
#   initial=[2, ],
#   choices=((1, '上海'), (2, '北京'),),
#   widget=widgets.CheckboxSelectMultiple
# )

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

如果内建的字段不能满足你的需求,你可以很容易地创建自定义的字段。你需要创建django.forms.Field 的一个子类。它只要求实现一个clean() 方法和接收上面核心参数的init() 方法(required, label, initial, widget, help_text)。

#方法一:
from app01 import models
class DBForm(DForms.Form):
  host = fields.CharField()
  host_type = fields.IntegerField(
    widget=widgets.Select(choices=[])
  )
  def __init__(self,*args, **kwargs):
    # 执行父类的构造方法
    super(DBForm,self).__init__(*args, **kwargs)
    self.fields['host_type'].widget.choices = models.UserType.objects.all().values_list('id','caption')
#方法二:使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现
from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
class FInfo(forms.Form):
  authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
  # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

自定义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开头')],
  )
# 方法二
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('手机号码格式错误')
phone = fields.CharField(validators=[mobile_validate, ],
              error_messages={'required': '手机不能为空'},
              widget=widgets.TextInput(attrs={'class': "form-control",
                             'placeholder': u'手机号码'}))
#方法三
from django import forms
  from django.forms import fields
  from django.forms import widgets
  from django.core.exceptions import ValidationError
  from django.core.validators import RegexValidator
  class FInfo(forms.Form):
    username = fields.CharField(max_length=5,
                  validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )
    email = fields.EmailField()
    def clean_username(self):
      """
      Form中字段中定义的格式匹配完之后,执行此方法进行验证
      :return:
      """
      value = self.cleaned_data['username']
      if "666" in value:
        raise ValidationError('666已经被玩烂了...', 'invalid')
      return value

同时生成多个标签验证:

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
############## 自定义字段 ##############
class PhoneField(fields.MultiValueField):
  def __init__(self, *args, **kwargs):
    # Define one message for all fields.
    error_messages = {
      'incomplete': 'Enter a country calling code and a phone number.',
    }
    # Or define a different message for each field.
    f = (
      fields.CharField(
        error_messages={'incomplete': 'Enter a country calling code.'},
        validators=[
          RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),
        ],
      ),
      fields.CharField(
        error_messages={'incomplete': 'Enter a phone number.'},
        validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],
      ),
      fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
        required=False,
      ),
    )
    super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,
                     **kwargs)
  def compress(self, data_list):
    """
    当用户验证都通过后,该值返回给用户
    :param data_list:
    :return:
    """
    return data_list

希望本文所述对大家基于Django框架的Python程序设计有所帮助。

您可能感兴趣的文章:

加载全部内容

相关教程
猜你喜欢
用户评论