Django中form组件
form组件简介
主要作用
- 数据校验 (对用户提交的数据格式进行校验)
- 生成html标签 + 携带数据(保留原来提交的数据,不再担心form表单提交时页面刷新;编辑页面显示默认值)
- 前端页面显示错误信息
特征:
form组件可以脱离数据库,当我们有对数据校验的需求时,就可以用form组件进行数据校验。
前端不同提交方式作用:
1、form表单提交
2、ajax提交
- 数据校验,对用户提交的数据格式校验
Form组件使用
默认是英文错误提示信息,如何修改为中文?
方法1:
修改settings.py
# LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'zh-hans'
方法2:
自定义错误信息error_messages字典
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'tian' __data__ = '2022/9/26 11:16' # software: PyCharm from django import forms class UserForm(forms.Form): use = forms.CharField(min_length=5,max_length=13,error_messages={"required":"用户名不能为空"}) pwd = forms.CharField(error_messages={"required":"密码不能为空"}) email = forms.EmailField(error_messages={"required":"邮箱不能为空","invalid":"邮箱格式错误"})
error_messages字典中可以写多种错误信息。
常用三个方法:
is_valid() form组件类中定义的所有字段,都通过其规则校验的话,返回True,有一项或者若干项校验失败,返回False。
cleaned_data 只有先经过is_valid校验后,才能使用该方法进行获取干净的数据。
errors 校验失败的错误信息,是个字典,存放一个或多个错误信息。
示例:
models.py
class UserProfile(models.Model): """ 用户表 """ user = models.CharField(verbose_name="用户名",max_length=32) pwd = models.CharField(verbose_name="密码",max_length=64) email = models.EmailField(verbose_name="邮箱",max_length=32) def __str__(self): return self.user
from django.contrib import admin from django.urls import path from web.views import formviews urlpatterns = [ path('admin/', admin.site.urls), path('register/', formviews.register, name="register"), ]
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'tian' __data__ = '2022/9/26 11:09' # software: PyCharm from django.shortcuts import redirect,render,HttpResponse,reverse from web.forms.bookform import UserForm from web import models def register(request): if request.method == "POST": forms_obj = UserForm(request.POST) if forms_obj.is_valid(): # 必须先进行is_valid,才能获取 models.UserProfile.objects.create(**forms_obj.cleaned_data) return HttpResponse("注册用户成功") else: # 错误信息包含在forms_obj对象中,前端通过该模板对象进行提取 return render(request,"register.html",{"forms_obj":forms_obj}) return render(request,"register.html")
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>form组件</title> <style> .errorMsg { color: red; margin-left: 10px; } </style> </head> <body> <form action="" method="post"> {% csrf_token %} <p>用户名 <input type="text" name="user"> <span class="errorMsg">{{ forms_obj.errors.user.0 }}</span></p> <p>密 码 <input type="password" name="pwd"> <span class="errorMsg">{{ forms_obj.errors.pwd.0 }}</span></p> <p>邮 箱 <input type="text" name="email"> <span class="errorMsg">{{ forms_obj.errors.email.0 }}</span></p> <p><input type="submit"></p> </form> </body> </html>
以上最基础的示例,存在很多问题:
- 返回错误信息时,没有问题的字段内容,由于页面刷新也被清空了
- 自定义更多更复杂的校验规则,如两次密码输入不一致的问题等等
form组件提供几种前端标签渲染方式
基础版
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'tian' __data__ = '2022/9/26 11:16' # software: PyCharm from django import forms class UserForm(forms.Form): use = forms.CharField(min_length=5,max_length=13,error_messages={"required":"用户名不能为空"}) pwd = forms.CharField(error_messages={"required":"密码不能为空"}) email = forms.EmailField(error_messages={"required":"邮箱不能为空","invalid":"邮箱格式错误"})
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'tian' __data__ = '2022/9/26 11:16' # software: PyCharm from django import forms class UserForm(forms.Form): user = forms.CharField(min_length=5,max_length=13,error_messages={"required":"用户名不能为空"}) pwd = forms.CharField(error_messages={"required":"密码不能为空"}) email = forms.EmailField(error_messages={"required":"邮箱不能为空","invalid":"邮箱格式错误"})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>form组件</title> <style> .errorMsg { color: red; margin-left: 10px; } </style> </head> <body> <form action="" method="post"> {% csrf_token %} <p>用户名 <input type="text" name="user"> <span class="errorMsg">{{ forms_obj.errors.user.0 }}</span></p> <p>密 码 <input type="password" name="pwd"> <span class="errorMsg">{{ forms_obj.errors.pwd.0 }}</span></p> <p>邮 箱 <input type="text" name="email"> <span class="errorMsg">{{ forms_obj.errors.email.0 }}</span></p> <p><input type="submit"></p> </form> </body> </html>
这种方式最大的问题,就是数据校验不通过,前端页面因为刷新,导致没问题的input的值也没了;
中级版
这个版本倒是省心省力,前端input标签不需要自己写,form组件帮我们做了,但也因此少了灵活性,用的也少,后端代码不需要做特殊处理,记得form标签需要加novalidate(目的是避免浏览器帮我们做数据校验),csrf_token和提交按钮不会自动生成,还需要我们自己处理。
特点就是错误信息需要我们手动处理,但解决前端页面因为刷新,导致没问题的input的值没了的问题。
# 进阶版 def register(request): if request.method == "POST": forms_obj = UserForm(request.POST) if forms_obj.is_valid(): # 必须先进行is_valid,才能获取 models.UserProfile.objects.create(**forms_obj.cleaned_data) return HttpResponse("注册用户成功") else: # 前端input标签中没有错误的输入值会保留,这里返回给前端 return render(request, "register.html", {"forms_obj": forms_obj}) # 需要在给页面的的时候,就传递一个forms_obj对象,方便生成相应的标签 forms_obj = UserForm() return render(request, "register.html",{"forms_obj":forms_obj})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>form组件</title> <style> .errorMsg { color: red; margin-left: 10px; } </style> </head> <body> <form action="" method="post" novalidate> {% csrf_token %} <!-- 直接as_p 啥都有了 --> {{ forms_obj.as_p }} <p><input type="submit"></p> </form> </body> </html>
高级版
前端代码部分手写,使用比较多。当有错误提示时,没有错误的字段输入值会保留。
views.py
def register(request): if request.method == "POST": forms_obj = UserForm(request.POST) if forms_obj.is_valid(): # 必须先进行is_valid,才能获取 models.UserProfile.objects.create(**forms_obj.cleaned_data) return HttpResponse("注册用户成功") else: return render(request, "register.html", {"forms_obj": forms_obj}) # 需要在给页面的的时候,就传递一个forms_obj对象,方便生成相应的标签 forms_obj = UserForm() return render(request, "register.html",{"forms_obj":forms_obj})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>form组件</title> <style> .errorMsg { color: red; margin-left: 10px; } </style> </head> <body> <form action="" method="post" novalidate> {% csrf_token %} <!--想渲染什么字段,就forms对象点啥字段 --> <p>用户名 {{ forms_obj.user }}<span class="errorMsg">{{ forms_obj.errors.user.0 }}</span></p> <p>密 码 {{ forms_obj.pwd }}<span class="errorMsg">{{ forms_obj.errors.pwd.0 }}</span></p> <p>邮 箱 {{ forms_obj.email }}<span class="errorMsg">{{ forms_obj.errors.email.0 }}</span></p> <p><input type="submit"></p> </form> </body> </html>
最终版(常用版)
这个版本中,后端加上了更多的内容,例如:渲染标签时,添加一些属性值,让其具有相应的样式。使用到booststrap。
views.py
def register(request): if request.method == "GET": form_obj = UserForm() return render(request, "register.html", {"forms_obj": form_obj}) form_obj = UserForm(request.POST) if not form_obj.is_valid(): return render(request, "register.html", {"forms_obj": form_obj}) User.objects.create(**form_obj.cleaned_data) return HttpResponse("添加成功")
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'tian' __data__ = '2022/9/26 11:16' # software: PyCharm from django import forms from django.forms import widgets class UserForm(forms.Form): user = forms.CharField( min_length=5, max_length=13, error_messages={"required": "用户名不能为空"}, widget=widgets.TextInput(attrs={"class": "form-control"}), label='用户名' ) pwd = forms.CharField( error_messages={"required": "密码不能为空"}, widget=widgets.PasswordInput(attrs={"class": "form-control"}), label="密码" ) email = forms.EmailField( error_messages={ "required": "邮箱不能为空", "invalid": "邮箱格式错误" }, widget=widgets.EmailInput(attrs={"class": "form-control"}), label="邮箱" )
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>form组件</title> <style> .errorMsg { color: red; margin-left: 10px; } </style> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-lg-offset-2"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in forms_obj %} <div class="form-group"> <label for={{ field.id_for_label }}>{{ field.label }}</label> <!-- 渲染input标签,并在有错误提示时渲染该错误信息 --> {{ field }} <span class="errorMsg">{{ field.errors.0 }}</span> </div> {% endfor %} <p><input type="submit" class="btn btn-success pull-left"></p> </form> </div> </div> </div> </body> </html>
自定义规则(钩子方法)
作用:在现有的校验基础上,如最大长度、最短长度限制、不能输入为空这些基础上,根据需求实现一些具体的校验规则,我们通常将这些自定义的校验规则,称之为钩子方法。
钩子方法分为:
- 局部钩子方法
- 全局钩子方法
加上基础校验,就有了三种校验规则,执行流程如下:
- 基础校验,每个字段内部(required + validators + min_length=6,max_length=10)
- 自定义局部钩子方法,当该字段的基础校验通过后,才执行的自定义的钩子校验方法。
- 全局钩子校验,无论基础校验和和自定义钩子方法是否通过,最后都会走全局钩子方法。
局部钩子
局部钩子针对某个字段设定的自定义校验规则,钩子方法在form组件类中以方法形式展现,想要对哪个字段进行自定义钩子,就以clean_开头,拼接字段名就可以了,如clean_user就是对user字段添加自定义钩子方法。
实例:使用局部钩子对密码一致性进行校验
在注册时,通常有密码和确认密码选项,但是数据库一般只有一个密码字段,所以,在开发中,要对用户输入的两个密码进行一致性校验。在校验时,注意点:
- form组件类中要重新生成一个确认密码的输入框字段,且该字段必须在密码字段下面,这是因为form组件中,校验是for循环每个字段校验的,在自定义钩子方法中,一般只能从cleaned_data中获取到当前字段和之前字段校验成功的数据,后面的字段数据由于还没循环到,导致没有添加到cleaned_data中,获取不到。
- 如果校验都通过了,写入到数据库之前,要把确认密码字段的数据删除掉,因为数据库中没有确认密码这个字段,不删除,可能会导致报错,因为多了个键值对,对应不上了!当然,这还要看你具体的orm语句是如何处理的。
views.py
def register(request): if request.method == "GET": form_obj = UserForm() return render(request, "register.html", {"forms_obj": form_obj}) form_obj = UserForm(request.POST) if not form_obj.is_valid(): return render(request, "register.html", {"forms_obj": form_obj}) User.objects.create(**form_obj.cleaned_data) return HttpResponse("添加成功")
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'tian' __data__ = '2022/9/26 11:16' # software: PyCharm from django import forms from django.forms import widgets from django.core.exceptions import ValidationError from web.models import UserProfile class UserForm(forms.Form): user = forms.CharField( min_length=5, max_length=13, error_messages={"required": "用户名不能为空"}, widget=widgets.TextInput(attrs={"class": "form-control"}), label='用户名' ) pwd = forms.CharField( min_length=6, error_messages={"required": "密码不能为空"}, widget=widgets.PasswordInput(attrs={"class": "form-control"}), label="密码" ) re_pwd = forms.CharField( min_length=6, error_messages={"required": "密码不能为空"}, widget=widgets.PasswordInput(attrs={"class":"form-control"}), label="确认密码" ) email = forms.EmailField( error_messages={ "required": "邮箱不能为空", "invalid": "邮箱格式错误" }, widget=widgets.EmailInput(attrs={"class": "form-control"}), label="邮箱" ) def clean_user(self): """自定义关于user字段的钩子方法,作用:用户名不能重复""" # 前端传递过来的user字段值 value = self.cleaned_data.get("user") user_obj = UserProfile.objects.filter(user=value).first() if user_obj: # 用户名已存在 # 固定写法 raise ValidationError("用户名已存在") else: # 如果用户名不存在,表示该字段值没问题,正常返回该值就行了 return value def clean_pwd(self): """自定义关于pwd字段的钩子方法,作用:密码不能是纯数字""" value = self.cleaned_data.get("pwd") if value.isdecimal(): raise ValidationError("密码不能是纯数字") else: return value def clean_re_pwd(self): re_pwd = self.cleaned_data.get('re_pwd') pwd = self.cleaned_data.get('pwd') if pwd is None: # 表示密码字段没有输入值,这里直接放行,反正密码钩子校验也通不过,这里钩子不校验也无所谓了 return re_pwd # 如果密码字段校验都没问题,这里直接判断两个值是否相等就行了 if re_pwd and pwd and re_pwd == pwd: return re_pwd else: raise ValidationError("两次密码输入不一致")
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>form组件</title> <style> .errorMsg { color: red; margin-left: 10px; } </style> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-lg-offset-2"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in forms_obj %} <div class="form-group"> <label for={{ field.id_for_label }}>{{ field.label }}</label> <!-- 渲染input标签,并在有错误提示时渲染该错误信息 --> {{ field }} <span class="errorMsg">{{ field.errors.0 }}</span> </div> {% endfor %} <p><input type="submit" class="btn btn-success pull-left"></p> </form> </div> </div> </div> </body> </html>
全局钩子
根据form组件的源码执行流程,当基础钩子和局部钩子都通过后,这时的cleaned_data数据也基本上是合法且完整的了,可以在全局钩子做最后的校验规则的补充。
全局钩子的基本使用和注意事项
在form组件类中重写clean
方法,即是在定义全局钩子。
全局钩子的校验逻辑是,通过校验,返回cleaned_data,否则raise ValidationError错误,错误信息将会保存在forms对象non_field_errors()方法中,前端通过form对象调用:{{ forms_obj.non_field_errors.0 }}
def register(request): if request.method == "GET": form_obj = UserForm() return render(request, "register.html", {"forms_obj": form_obj}) form_obj = UserForm(request.POST) # print(form_obj.errors) # print("全局钩子中的错误",form_obj.errors.get("__all__")) if not form_obj.is_valid(): form_obj.non_field_errors() # 全局钩子错误信息 return render(request, "register.html", {"forms_obj": form_obj}) User.objects.create(**form_obj.cleaned_data) return HttpResponse("添加成功")
class UserForm(forms.Form): user = forms.CharField( label="用户名", min_length=4, max_length=13, error_messages={"required": "该字段不能为空"}, widget=forms.TextInput(attrs={"class":"form-control"}) ) pwd = forms.CharField( label="密码", error_messages={"required": "该字段不能为空"}, widget=forms.PasswordInput(attrs={"class":"form-control"}), ) email = forms.EmailField( label="邮箱", widget=forms.EmailInput(attrs={"class":"form-control"}), error_messages={ "required": "该字段不能为空", "invalid": "邮箱格式错误" } ) def clean(self): if self.cleaned_data.get("user") == "tian": print("全局校验进入了") raise ValidationError("全局错误了")
<html lang="en"> <head> <meta charset="UTF-8"> <title>form组件</title> <style> .errorMsg { color: red; margin-left: 10px; } </style> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-lg-offset-2"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in forms_obj %} <div class="form-group"> <label for="">{{ field.label }}</label> <!-- 渲染input标签,并在有错误提示时渲染该错误信息 --> {{ field }} <span class="errorMsg">{{ field.errors.0 }}</span> </div> {% endfor %} <h1>{{ forms_obj.non_field_errors.0 }}</h1> <!--全局钩子错误信息--> <p><input type="submit" class="btn btn-success pull-left"></p> </form> </div> </div> </div> </body> </html>
重写__init__方法
如果form组件类中,每个字段都要写required,添加属性值之类的,在每个字段中写是非常麻烦,可以将相同的值在__init__中写:
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'tian' __data__ = '2022/9/26 11:16' # software: PyCharm from django import forms from django.forms import widgets from django.core.exceptions import ValidationError from web.models import UserProfile class UserForm(forms.Form): user = forms.CharField( min_length=5, max_length=13, error_messages={"required": "用户名不能为空"}, widget=widgets.TextInput(), label='用户名' ) pwd = forms.CharField( min_length=6, error_messages={"required": "密码不能为空"}, widget=widgets.PasswordInput(), label="密码" ) re_pwd = forms.CharField( min_length=6, error_messages={"required": "密码不能为空"}, widget=widgets.PasswordInput(), label="确认密码" ) email = forms.EmailField( error_messages={ "required": "邮箱不能为空", "invalid": "邮箱格式错误" }, widget=widgets.EmailInput(), label="邮箱" ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 为所有的字段添加相同的属性 for field in self.fields.values(): field.widget.attrs.update({"class": "form-control"}) field.error_messages.update({"required": "该字段不能为空"})
forms处理下拉菜单
下拉菜单处理分为几种情况:
单选下拉框
- 值是固定的,用户表的性别字段,值是固定的,多选一,这种情况前端搞个单选下拉框即可。
- 值是动态的,下拉框的值是外键字段关联的表中的数据,例如书籍表的出版社字段,它关联出版社表,前端展示书籍对应的出版社字段时,数据是从出版社表中动态获取的,所以这个单选下拉框跟上面的下拉框还不一样。
多选下拉框
- 多选下拉框的值通常也来自外键字段,例如书籍的作者字段对应作者表,这种情况的多选下拉框跟上面的下拉框还不一样。
下面示例,涵盖了上面三种下拉框
mdels.py
class Book(models.Model): """书""" title = models.CharField(max_length=32, verbose_name="书名") price = models.DecimalField(max_digits=5, decimal_places=2) pub_date = models.DateTimeField(auto_now_add=True) publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE) authors = models.ManyToManyField(to="Author") class Publish(models.Model): """出版社""" name = models.CharField(max_length=32) city = models.CharField(max_length=64) email = models.EmailField() def __str__(self): return self.name class Author(models.Model): """ 作者 """ name = models.CharField(max_length=32, verbose_name="用户名") gender = models.IntegerField(choices=((1, "男"), (2, "女")), default=1, verbose_name="性别") age = models.SmallIntegerField() au_detail = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE) def __str__(self): return self.name class AuthorDetail(models.Model): """ 作者详细信息 """ gender_choices = ( (0, "女"), (1, "男"), (2, "保密"), ) gender = models.SmallIntegerField(choices=gender_choices, default=1, verbose_name="性别") tel = models.CharField(max_length=32) addr = models.CharField(max_length=64) birthday = models.DateField(auto_now_add=True)
from django.contrib import admin from django.urls import path from web.views import formviews urlpatterns = [ path('add_book/', formviews.add_book, name="add_book"), path('add_author/', formviews.add_author, name="add_author"), ]
from django.shortcuts import redirect, render, HttpResponse, reverse from web.forms.bookform import UserForm,BookForm,AuthorForm from web import models def add_book(request): """添加书籍""" if request.method == "POST": forms_obj = BookForm(request.POST) if forms_obj.is_valid(): data = forms_obj.cleaned_data # print(data) # queryset对象 # print(list(data['authors'])) # print(data['publish']) obj = models.Book.objects.create( title=data['title'], price=data['price'], pub_date=data['pub_date'], publish=data['publish'] ) obj.authors.add(*data['authors']) return HttpResponse("OK") else: return render(request, 'register.html', {"forms_obj": forms_obj}) forms_obj = BookForm() return render(request, 'add_author.html', {"forms_obj": forms_obj}) def add_author(request): """ 添加作者 """ if request.method == "POST": forms_obj = AuthorForm(request.POST) if forms_obj.is_valid(): # print(forms_obj.cleaned_data) models.Author.objects.create(**forms_obj.cleaned_data) return HttpResponse("OK") else: return render(request, 'register.html', {"forms_obj": forms_obj}) forms_obj = AuthorForm() return render(request, 'add_author.html', {"forms_obj": forms_obj})
from django import forms from django.forms import widgets from django.core.exceptions import ValidationError from web.models import UserProfile,Publish,Author,Book class AuthorForm(forms.Form): user = forms.CharField(label="作者名") # 值是固定的单选下拉框,initial=2初始值为女 gender = forms.ChoiceField(choices=((1,"男"),(2,"女")),label="性别",initial=2) def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) for field in self.fields.values(): field.widget.attrs.update({"class":'form-control'}) field.error_messages.update({"required":"该字段不能为空"}) class BookForm(forms.Form): title = forms.ChoiceField(label="书籍名") price = forms.DecimalField(max_digits=4,decimal_places=2,label="价格") pub_date = forms.DateField(label="出版时间",widget=widgets.TextInput(attrs={"type":"date"})) # 值是动态的单选下拉框 publish = forms.ModelChoiceField(queryset=Publish.objects.all().order_by("-pk"),label="出版社",empty_label="请选择") # 值是动态的多选下拉框 authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all(),label="作者") def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) for field in self.fields.values(): field.widget.attrs.update({"class":"form-control"}) field.error_messages.update({"required": "该字段不能为空"})
add_book.html 和 add_author.html(两个代码一样)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>form组件</title> <style> .errorMsg { color: red; margin-left: 10px; } </style> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-lg-offset-2"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in forms_obj %} <div class="form-group"> <label for="">{{ field.label }}</label> {{ field }} <span class="errorMsg">{{ field.errors.0 }}</span> </div> {% endfor %} <p><input type="submit" class="btn btn-success pull-left"></p> </form> </div> </div> </div> </body> </html>
form组件补充
django内置字段
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 是否移除用户输入空白 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内置插件:
extInput(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 # )