django基础之Form组件和ModelForm

django基础之Form组件和ModelForm

一.form介绍

form组件的主要功能:

1.生成页面可用的HTML标签

2.对用户提交的数据进行检验

3.保留上次输入内容 #render_value,一般密码的默认值为False

二.Form常用字段与插件

initial 设置input框里的默认值

initial="张三"

error_messages 设置错误信息

error_messages={
          "required": "不能为空",
          "invalid": "格式错误",
          "min_length": "用户名最短8位"
      }

radioSelect 单radio值为字符串

CheckboxInput 单选

CheckboxSelectMultiple 多选

Select 单选下拉框

SelectMutiple 多选下拉框

date 时间类型 attrs={'type':'date'}

 

三.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类型
复制代码

 

简单例子:
form组件内容:

max_length=32,    #设置最大长度
min_length=4,    #设置做小长度
label='书名',     #设置标签名
required=False,   #设置输入框内容不能为空Flase,为空True
​
widget=forms.widgets.TextInput(attrs={'class':'form-control'})
                #通过widget可以给输入框设置格式 attrs
widget=forms.widgets.DateInput(attrs={'class': 'form-control','type':'date'})
        #这块如果需要时间输入框中有时间表可供选择,就需要再attrs字典中添加type
        
​
publish_s=forms.ModelChoiceField(
    #单选下拉框就用ModelChoiceField
    queryset=models.Publish.objects.all(),   #queryset获取对应表中的信息
    widget=forms.widgets.Select(attrs={'class': 'form-control'})
        #单选,widget设置成select
)
​
author = forms.ModelMultipleChoiceField(
        # 多选下拉框就用ModelMultipleChoiceField
        queryset=models.Author.objects.all(),
        widget=forms.widgets.SelectMultiple(attrs={'class': 'form-control'})
        # 多选,widget设置成SelectMultiple
    )

 




view视图内容

from django.shortcuts import render,HttpResponse,redirect
from app01.myform import  Myform,Zhuce
from app01 import models
# Create your views here.
​
​
​
def index(request):
​
    if request.method=='GET':
        book_objs=Myform()
        return  render(request,'index.html',{'book_objs':book_objs})
​
​
​
    else:
        data=request.POST       #这样获取的数据可以得到书名,价格等,但是不能得到出版社和作者姓名,只有id号,
                                # 还得进行麻烦的数据处理,form组件提供有方法可以省去麻烦的步骤,
                                #所以先通过form组件实例化
        print(data)
        book_objs=Myform(data)   #将获得的数据实例化
        if book_objs.is_valid():   #验证获取的数据是否正确
            data=book_objs.cleaned_data  #form组件提供的方法,获取前端页面输入框用户输入的内容
            author_data=data.pop('author')
                            # 从页面获取的值,这块的'author'变量名要填写form文件中的命名
            book_obj=models.Book.objects.create(**data)
            book_obj.author_s.add(*author_data)
                            #这块的authorss是book表与author表的关系字段,起名是啥必须写啥
            return HttpResponse('ok')
​
        else:
            # return HttpResponse('输入有误')
            print(book_objs.errors)
        return render(request,'index.html',{'book_objs':book_objs})

 


   
   
HTML页面内容    
<div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <form action="" method="post" novalidate>
                {% csrf_token %}
                          #csrf验证
                    {% for book_obj in book_objs %}
                        <div class="form-group {% if book_obj.errors.0  %}has-error{% endif %}">                        #这块条件判断,如果用户输入内容有误,就显示错误信息
                            <label for="{{ book_obj.id_for_label }}">{{ book_obj.label }}</label>                                   #这个class属性设置上点击标签内容就可定位到输入框
                            {{ book_obj }}
                            <span class="text-danger">{{ book_obj.errors.0 }}</span>
                                        #在这块将错误信息呈现在页面上
                        </div>
                    {% endfor %}
                <input type="submit">
                </form>
            </div>
        </div>
    </div>

 

 

 

HOOK钩子方法

局部钩子

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

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        },
        widget=forms.widgets.TextInput(attrs={"class": "form-control"})
    )
    ...
    # 定义局部钩子,用来校验username字段,之前的校验股则还在,给你提供了一个添加一些校验功能的钩子
    def clean_username(self):
        value = self.cleaned_data.get("username")
        if "666" in value:
            raise ValidationError("光喊666是不行的")
        else:
            return value

 

全局钩子

我们在Fom类中定义 clean() 方法,就能够实现对字段进行全局校验,字段全部验证完,局部钩子也全部执行完之后,执行这个全局钩子校验。

class LoginForm(forms.Form):
    ...
    password = forms.CharField(
        min_length=6,
        label="密码",
        widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True)
    )
    re_password = forms.CharField(
        min_length=6,
        label="确认密码",
        widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True)
    )
    ...
    # 定义全局的钩子,用来校验密码和确认密码字段是否相同,执行全局钩子的时候,cleaned_data里面肯定是有了通过前面验证的所有数据
    def clean(self):
        password_value = self.cleaned_data.get('password')
        re_password_value = self.cleaned_data.get('re_password')
        if password_value == re_password_value:
            return self.cleaned_data #全局钩子要返回所有的数据
        else:
            self.add_error('re_password', '两次密码不一致') #在re_password这个字段的错误列表中加上一个错误,并且clean_data里面会自动清除这个re_password的值,所以打印clean_data的时候会看不到它
            raise ValidationError('两次密码不一致')

 

posted @ 2019-08-14 20:33  socoolonly1  阅读(139)  评论(0编辑  收藏  举报