Form组件认证

能够帮助我们做用户认证。

以前写我们自己写用户认证的时候,我们自己写HTML的form表单,点击提交,数据就被发送到后台,后台进行验证。在验证过程中我们就需要自己去写正则表达式去匹配相关的数据信息。

但是!

django中有一个叫做form组件的东西,他是专门做这个验证的,我们可以利用form创造一个模板,接下来如果请求发过来,我们把request.post里面的东西发给这个模板,那这个模板就能够一个一个的进行请求验证。他会产生三个结果:是否验证成功,所有的正确信息,所有的错误信息。

那这个神奇的form模板是什么?怎么创建的呢?

 from django import forms
class FM(forms.Form):
#字段名必须要和HTML中的name值一样,否则拿不到数据
user = forms.CharField()
pwd = forms.CharField()
email = forms.EmailField() def fm(request):
if request.method == 'GET':
return render(request,'fm.html')
elif request.method == 'POST':
obj = FM(request.POST)
r1 = obj.is_valid()
if r1:
print(obj.cleaned_data)
else:
print(obj.errors.as_json())
return redirect('/fm/')

首先我们要创建一个类,这个类要继承form.Form。然后在里面接受数据做判断。注意:字段名要和html中的name值一样,否则拿不到数据

在form 验证的函数中,我们要传入的就是request.POST,用is_valid()就可以接收返回的结果,obj.cleaned_data返回的是正确的结果,obj.errors是返回错误的结果。as_json()设置返回数据以json形式返回

那我们看错误信息返回的都是英文,我们能不能定义一下错误信息的形式呢?

 class FM(forms.Form):
#字段名必须要和HTML中的name值一样,否则拿不到数据
user = forms.CharField(error_messages={'required':'用户名不能为空'})
pwd = forms.CharField(
max_length=12,
min_length=6,
error_messages={'required':'用户名不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'}
)
email = forms.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'})

这样就显示了我们也想要的错误信息。

那我们可以把这些显示错误信息传到前端:(通过字典的形式去拿)

return render(request, 'fm.html',{'obj':obj})
 <form action="/fm/" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="user" >{{ obj.errors.user.0 }}</p>
<p>密码:<input type="password" name="pwd" >{{ obj.errors.pwd.0 }}</p>
<p>邮箱:<input type="text" name="email" >{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交" >
</form>

这样就能够显示出错误信息

但是现在还有一个问题是,点击了提交之后,错误信息是显示出来了,但是input里面的数据不见了。那怎么解决呢?

其实django不光能够生成这个错误,还能够生成html:

<form action="/fm/" method="post">
{% csrf_token %}
<p>用户名:{{ obj.user }}{{ obj.errors.user.0 }}</p>
<p>密码:{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
<p>邮箱:{{ obj.email }}{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交" >
</form>

views.py:

 from app01 import models
def fm(request):
if request.method == 'GET':
obj = FM()
5 return render(request,'fm.html',{'obj':obj})
elif request.method == 'POST':
obj = FM(request.POST)
r1 = obj.is_valid()
if r1:
models.UserInfo.objects.create(**obj.cleaned_data)
else:
print(obj.errors)
return render(request, 'fm.html',{'obj':obj})

只要我们在get的时候也生成一个对象,这时候不需要传入什么数据,然后把这个对象传过去就可以了。最后我们如果验证成功了,直接create(**obj.cleaned_data)就可以了。

当然全段的生成还有一些简单的方法:as_p,as_ul,as_table

 <form action="/fm/" method="post">
{% csrf_token %}
{{ obj.as_p }}
<input type="submit" value="提交" >
</form>

 <form action="/fm/" method="post">
{% csrf_token %}
{{ obj.as_ul }}
<input type="submit" value="提交" >
</form>

 <form action="/fm/" method="post">
{% csrf_token %}
<table>
{{ obj.as_table }}
</table>
<input type="submit" value="提交" >
</form>

但是这种方式,虽然方便,但是可定制性不高!

下面我们来看看怎么样设置form里面的样式:

 from django import forms
from django.forms import widgets
from django.forms import fields
class FM(forms.Form):
#字段本身只做验证
#字段名必须要和HTML中的name值一样,否则拿不到数据
user = fields.CharField(
error_messages={'required':'用户名不能为空'},
widget=widgets.Input(attrs={'class':'c1'})
)
pwd = fields.CharField(
max_length=12,
min_length=6,
error_messages={'required':'用户名不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'},
widget=widgets.PasswordInput
)
email = fields.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'})

字段本身只做插件,在CharField中继承了一个Field类,然后查看里面:

其实就是做了一些字符串的拼接操作,

我们就可以通过widgets进行设置input的类型,如果要设置里面的样式,可以使用attr()方法,在里面添加

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

我们看一下label标签:

class FM(forms.Form):
label="用户名",
)
pwd = fields.CharField(
label="密码", )
email = fields.EmailField(
label="邮箱",
)
<form action="/fm/" method="post">
{% csrf_token %}
<p>{{ obj.user.label }}{{ obj.user }}{{ obj.errors.user.0 }}</p>
<p>{{ obj.pwd.label }}{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
<p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交" >
</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'邮箱'}))

方式三:自定义方法

 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 "" 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 ############## 自定义插件 ##############
class SplitPhoneWidget(widgets.MultiWidget):
def __init__(self):
ws = (
widgets.TextInput(),
widgets.TextInput(),
widgets.TextInput(),
)
super(SplitPhoneWidget, self).__init__(ws) def decompress(self, value):
"""
处理初始值,当初始值initial不是列表时,调用该方法
:param value:
:return:
"""
if value:
return value.split(',')
return [None, None, None]

常用选择插件:

单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的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的

方式一:

 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.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
) def __init__(self, *args, **kwargs):
super(MyForm,self).__init__(*args, **kwargs)
# self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].widget.choices = models.Classes.objects.all().value_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())

初始化操作:

我们一般做get的请求的时候都是查询到数据之后再页面上显示的,那么我们如何为表单设置初值呢?

html:

 <form action="/fm/" method="post">
{% csrf_token %}
<p>{{ obj.user.label }}{{ obj.user }}{{ obj.errors.user.0 }}</p>
<p>{{ obj.pwd.label }}{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
<p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}</p>
{{ obj.city }}
{{ obj.city1 }}
<input type="submit" value="提交" >
</form>

Form类:

 class FM(forms.Form):
#字段本身只做验证
#字段名必须要和HTML中的name值一样,否则拿不到数据
user = fields.CharField(
error_messages={'required':'用户名不能为空'},
widget=widgets.Input(attrs={'class':'c1'}),
label="用户名",
)
pwd = fields.CharField(
max_length=12,
min_length=6,
error_messages={'required':'用户名不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'},
widget=widgets.PasswordInput,
label="密码", )
email = fields.EmailField(
error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'},
label="邮箱",
)
p = fields.FileField()
city = fields.ChoiceField(
choices=((1,'上海'),(2,'北京')),
)
city1 = fields.MultipleChoiceField(
choices=((1, '上海'), (2, '北京')),
)

函数:

     if request.method == 'GET':
#从数据库中获得数据
dic = {
'user':'root',
'pwd':'',
'email':'123@123.com',
'city':1,
'city1':[1,2],
}
obj = FM(initial=dic)
return render(request,'fm.html',{'obj':obj})

很多时候,我们想要自行设计校验的手段,该如果做了,Django给我们提供了钩子这一手段

先来看一段源码:

if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value

这段源码是能够设置钩子的来源。

#局部钩子
def clean_user(self):
val1 = self.cleaned_data.get("user")
#如果这个字符串全部都是由数组组成
if not val1.isdigit():
return val1
else:
# 注意这个报错信息已经确定了
raise ValidationError("用户名不能全部是数字组成")

还可以设置全局钩子:

    def clean(self):
pwd=self.cleaned_data.get("pwd")
repeat_pwd=self.cleaned_data.get("repeat_pwd")
if pwd==repeat_pwd:
print("yes")
return self.cleaned_data
else:
print("no")
raise ValidationError("两次密码不一致!")

为什么有全局钩子了,因为每一个钩子都是和某个具体的字段绑定,只能获取自己的字段值,不能获取其他的值,所以需要全局钩子。

案例:

 from django.shortcuts import render,HttpResponse

 # Create your views here.

 from django import forms
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.forms import widgets
import re
from appo1 import models class LoginForm(forms.Form):
user = forms.CharField(min_length=6,max_length=12,
error_messages={
"required":"用户名不能为空",
"min_length":"最小长度为5",
"max_length":"最大长度为12"
},
widget=widgets.TextInput(attrs={"id":"s1"})
) pwd = forms.CharField(min_length=6,
error_messages={
"required":"密码不能为空",
"min_length":"最小长度为6"
}
) repeat_pwd = forms.CharField(
error_messages={
"required": "必须输入",
}
) email = forms.EmailField(
error_messages={
"required": "",
"invalid":"格式错误"
}
) phone = forms.CharField(
error_messages={
"required": "必须输入",
}
) #必须以clear起手,否则不能尽心检测
def clean_user(self):
import re
val1 = self.cleaned_data.get("user")
ret = re.findall(r'^_', val1) if not val1.isdigit():
if ret:
return val1
else:
raise ValidationError("必须以下划线开头")
else:
raise ValidationError("用户名不能全部为数字组成") def clean_pwd(self):
val2=self.cleaned_data.get("pwd")
if not val2.isdigit():
return val2
else:
raise ValidationError("密码不能全部为数字!") def clean_phone(self):
val3 = self.cleaned_data.get("phone")
if val3.isdigit():
if len(val3) != 11:
raise ValidationError("亲,号码是11位!")
else:
return val3
else:
raise ValidationError("号码必须是数字!") def clean(self):
pwd=self.cleaned_data.get("pwd")
repeat_pwd=self.cleaned_data.get("repeat_pwd")
if pwd==repeat_pwd:
print("yes")
return self.cleaned_data
else:
print("no")
raise ValidationError("两次密码不一致!") def login(request):
if request.method == "POST": form_obj = LoginForm(request.POST)
if form_obj.is_valid():
user = request.POST.get("user")
pwd = request.POST.get("pwd")
email = request.POST.get("email")
phone = request.POST.get("phone")
ret = models.user_info.objects.create(user=user,pwd=pwd,email=email,phone=phone)
return HttpResponse("你好,欢迎回来!")
else: ret = form_obj.errors.get("__all__")
#{{form_obj.repwd}} < span > {{form_obj.errors.repwd.0}}{{form_obj.non_field_errors.0}} < / span >
#还可以在前端直接传
return render(request, "login.html", {"form_obj": form_obj,"ret":ret}) form_obj = LoginForm()
return render(request,"login.html",{"form_obj":form_obj}) import json
def user_check(request):
response = {"is_reg": False}
user = request.POST.get("user")
ret = models.user_info.objects.filter(user=user)
print(ret)
if ret:
response["is_reg"] = True

ModelForm:

之前我们建立表单,通过建立Form类来创建,当然我们也可以直接通过model表来进行创建:

model.py:

from django.db import models

# Create your models here.
class UserType(models.Model):
caption = models.CharField(max_length=32) class UserInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to='UserType',to_field='id',on_delete=models.CASCADE)

views.py:

from django.shortcuts import render,redirect,HttpResponse
from django import forms
from django.forms import fields
from app01 import models class UserInfoModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo#去哪个类中获取字段
fields = '__all__' #展现所有字段,也可以制定# Create your views here.
def index(request):
if request.method=='GET':
obj = UserInfoModelForm()
return render(request,'index.html',{'obj':obj})
elif request.method=='POST':
obj = UserInfoForm(request.POST)
obj.is_valid() models.UserType.objects.create(**obj.cleaned_data)
return render(request, 'index.html', {'obj': obj})

html:

<form action="/index/" method="post">
{% csrf_token %}
{{ obj.as_p }}
<input type="submit" value="提交">
</form>

这个就相当于直接从表中拿出字段名称,进行创建表单。当然,我们在form类中能够用设置字段的中文,我们只需要在model.py中设置就可以了。

username = models.CharField(max_length=32,verbose_name="用户名")

在创建表单的时候有一个字段verbose_name, 这个在django_admin中显示中文,同样的在form中也是用的这个:

fields = '__all__':代指获得所有的字段,

  • 当然也可以是列表,如:fields = ['username'],那只会把username展示出来
  • 如果字段过多的话还有排除法:exclude=['username']这样就把除了username的字段都显示出来

modelForm验证:

ModelForm
a. class Meta:
model, # 对应Model的
fields=None, # 字段
exclude=None, # 排除字段
labels=None, # 提示信息
help_texts=None, # 帮助提示信息
widgets=None, # 自定义插件
error_messages=None, # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
field_classes=None # 自定义字段类 (也可以自定义字段)
localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据
如:
数据库中
2016-12-27 04:10:57
setting中的配置
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = True
则显示:
2016-12-27 12:10:57
b. 验证执行过程
is_valid -> full_clean -> 钩子 -> 整体错误 c. 字典字段验证
def clean_字段名(self):
# 可以抛出异常
# from django.core.exceptions import ValidationError
return "新值"
d. 用于验证
model_form_obj = XXOOModelForm()
model_form_obj.is_valid()
model_form_obj.errors.as_json()
model_form_obj.clean()
model_form_obj.cleaned_data
e. 用于创建
model_form_obj = XXOOModelForm(request.POST)
#### 页面显示,并提交 #####
# 默认保存多对多
obj = form.save(commit=True)
# 不做任何操作,内部定义 save_m2m(用于保存多对多)
obj = form.save(commit=False)
obj.save() # 保存单表信息
obj.save_m2m() # 保存关联多对多信息 f. 用于更新和初始化
obj = model.tb.objects.get(id=1)
model_form_obj = XXOOModelForm(request.POST,instance=obj)
... PS: 单纯初始化
model_form_obj = XXOOModelForm(initial={...})

labels:我们在不使用verbose_name下就可以把input的字段名变成中文:

labels = {
'username':'用户名',
'email' : '邮箱'
}

help_text:提示要填写的内容格式等,可以使用这个:

help_texts = {
'username':'....'
}

widgits:自定义组件:

  默认username字段用的是charfield,如果想要改变也是可以的

from django.forms import widgets as Fwidgets

        widgets = {
'username':Fwidgets.Textarea(attrs={'class':'c1'})
}

error_message:错误信息

默认的:

error_messages = {
        '__all__' :{}#定义整体的错误信息
'username':{ "required": "用户名不能为空"}
}

field_classes:字段类

field_classes = {
'email':Ffields.URLField,
}

这样email里面就只能够填写url的格式,而不是邮箱格式

现在想要用modelForm保存表单提交的数据到数据库中:

 obj = UserInfoModelForm(request.POST)
if obj.is_valid():
obj.save()

这样就可以提交保存到数据库

下面我们来看一个表单读取和修改的小例子:

view.py:

def user_list(request):
li = models.UserInfo.objects.all().select_related('user_type')
return render(request,'user_list.html',{'li':li})
def user_edit(request,nid):
#获取当前id对应的用户信息
#显示用户已经存在的数据
if request.method=="GET":
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(instance=user_obj)
return render(request,'user_edit.html',{'mf':mf,'nid':nid})
elif request.method == 'POST':
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(request.POST,instance=user_obj)
if mf.is_valid():
mf.save()
else:
print(mf.errors.as_json())
return redirect('/user_list/')

user_list.html:

<ul>
{% for row in li %}
<li>{{ row.username }}-{{ row.user_type.caption }}-<a href="/edit-{{ row.id }}/">编辑</a></li>
{% endfor %}
</ul>

user_edit.html:

<form action="/edit-{{ nid }}/" method="post">
{% csrf_token %}
{{ mf.as_p }}
<input type="submit" value="提交">
</form>

这里注意的是:

  • 外键的联合查询可以用select_related('外键名'),但是这个只是适用于1对多,不适合多对多的查询
  • 修改数据之前get获得数据,只需要在ModelForm中用参数instance就接受查询到的参数就可以了
  • 在修改之后如果要保存数据,也要先查询一下,然后把查询到的数据通过instance参数传入

Django学习---Form组件认证的更多相关文章

  1. 〖Python〗-- Django的Form组件

    [Django的Form组件] Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 Form类的使 ...

  2. Django之Form组件

    Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功能: 生成HTML标签 验证用户 ...

  3. Python之路【第二十一篇】:Django之Form组件

    Django之Form组件   Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1. ...

  4. 第十一篇:web之Django之Form组件

    Django之Form组件   Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功 ...

  5. python Django之Form组件

    python Django之Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试 ...

  6. Django之Form组件(一)

    Django之Form组件(一) Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 基本操作:字 ...

  7. python框架之Django(10)-Form组件

    介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来.与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入 ...

  8. Django之Form组件验证

    今天来谈谈Django的Form组件操作 Django中的Form一般有两种功能: ·输入html ·验证用户输入 Form验证流程 ·定义规则(是一个类)    ·前端把数据提交过来 ·匹配规则 · ...

  9. django 使用form组件提交数据之form表单提交

    django的form组件可以减少后台在进行一些重复性的验证工作,极大降低开发效率. 最近遇到一个问题: 当使用form表单提交数据后,如果数据格式不符合后台定义的规则,需要重新在前端页面填写数据. ...

随机推荐

  1. Java Spring-Bean中属性注入

    2017-11-06 20:29:13 类属性的注入的三种方法 1.接口方法注入 public interface injection{ public void setName(String name ...

  2. Learn Rails5.2- ActiveRecord: Migration , spring的使用(不兼容的解决办法)

    偶然一次: 运行rails generate停止不动,网上查找答案,可能是bundle update 之后 spring 版本变化了,和正在运行的 spring 实例不兼容. Spring导致的同样的 ...

  3. 13个能快速开发android的经典项目

    一.okhttp一个让网络请求更简单的框架 项目地址 https://github.com/jeasonlzy/okhttp-OkGo 二. TwinklingRefreshLayout-下拉刷新和上 ...

  4. AndroidStudio怎样导入library项目开源库

    AndroidStudio是一款非常强大的android程序开发软件,在里面集成了几乎所有android开发中需要使用的工具,编译.运行.打包.开发.调试等功能一应俱全,可以使用起来非常方便. 今天要 ...

  5. HDU - 4812 D Tree 点分治

    http://acm.hdu.edu.cn/showproblem.php?pid=4812 题意:有一棵树,每个点有一个权值要求找最小的一对点,路径上的乘积mod1e6+3为k 题解:点分治,挨个把 ...

  6. UVA-1617 Laptop (贪心)

    题目大意:有n条长度为1的线段,n个区间,第i条线段在第i个区间中,问线段之间的最少间隙有几个. 题目分析:先对区间排序,先按右端点排,再按左端点排.有重叠的区间(仅有交点重叠也视为重叠)之间一定可以 ...

  7. Integer与int的种种比较你知道多少

    如果面试官问Integer与int的区别:估计大多数人只会说道两点,Ingeter是int的包装类,int的初值为0,Ingeter的初值为null. 但是如果面试官再问一下Integer i = 1 ...

  8. docker把web jar包制作成镜像

    1.新建一个spring boot项目 并使用maven打成jar包,放到linux(centos7)环境上. 运行 java -jar hello.jar  后结果如下(这里项目对外提供的端口是90 ...

  9. prototype原型模式

    /** * 原型模式 Prototype * 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象 */ 需求: public class Resume { /** * 要求:一个简历类,必须 ...

  10. pandas 之 concat

    本文摘自:http://pandas.pydata.org/pandas-docs/stable/merging.html 前提: ide: liuqian@ubuntu:~$ ipython 准备: ...