目录
2、携带数据、 显示默认值(initial),做编辑页面显示默认值。
6、form.errors是一个dict对象,里面有很多方式,默认是ul>li
7、validators=[RegexValidator(r'^1[358]\d{9}$', '手机格式错误'), ],正则表达式
2、生成HTML标签 + 插件 + 和 参数的配置,基于BootStrap样式优化
2、方式二:bootstrapt样式化(self.fields['level'].queryset对象)
一、Form组件
1、form作用
1、生成HTML标签
- 保留原来提交的数据,不再担心form表单提交时页面刷新。
class LoginForm(forms.Form):
role = forms.ChoiceField(
label="角色",
required=True,
choices=(("2", "客户"), ("1", "管理员")),
widget=forms.Select(attrs={"class": "form-control"})
)
username = forms.CharField(
label="用户名",
widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "用户名"})
)
password = forms.CharField(
label="密码",
min_length=6,
max_length=10,
validators=[RegexValidator(r'^[0-9]+$', '密码必须是数字'), ], # 正则表达式
widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "密码"}, render_value=True)
)
2、携带数据、 显示默认值(initial),做编辑页面显示默认值。
在传入initial来指定html默认显示的值
#在传入initial时来指定默认显示的值
form=LoginForm(initial={"role":"xx","username":"xxx","password":"xxxx"})
3、数据校验,对用户提交的数据格式校验
form = LoginForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
else:
print(form.errors)
2、form校验流程
-
每个字段的内部:required + validators +
min_length=6,max_length=10
-
字段的钩子方法
-
def clean_username(self): user = self.cleaned_data['username'] # 校验规则 # 校验失败 if len(user) < 3: from django.core.exceptions import ValidationError raise ValidationError("用户名格式错误") return user print(form.cleaned_data)
-
clean(不管前面的字段有么有校验通过,都会执行)
-
def clean(self): # 对所有值进行校验 from django.core.exceptions import ValidationError # 1.不返回值,默认 self.cleaned_data # 2.返回值,self.cleaned_data=返回的值 # 3.报错,ValidationError -> self.add_error(None, e)
-
_post_clean
-
def _post_clean(self): pass
-
注意:在每个字段的钩子方法中,只有上一个字段校验通过后,才能在当前字段调用之前的字段,self.cleaned_data才会有字段
from django import forms
class SmsLoginForm(forms.Form):
role = forms.ChoiceField()
mobile = forms.CharField(
label="手机号",
validators=[RegexValidator(r'^1[358]\d{9}$', '手机格式错误'), ],
widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "手机号"})
)
code = forms.CharField()
def clean_code(self):
mobile = self.cleaned_data.get('mobile')
code = self.cleaned_data['code']
if not mobile:
return code
3、form字段的类型
1、forms.ChoiceField()
#Choice类型
role = forms.ChoiceField(
label="角色",
required=True,
choices=(("2", "客户"), ("1", "管理员")),
widget=forms.Select(attrs={"class": "form-control"})
)
2、forms.CharField()
mobile = forms.CharField(
label="手机号",
validators=[RegexValidator(r'^1[358]\d{9}$', '手机格式错误'), ],
widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "手机号"})
)
4、form字段参数
1、字段的label,label="角色",模板调用label用法<label for="{{ field.id_for_label }}">
2、当前字段的名字,field.name
3、required=True,必填项
4、 min_length=6,max_length=10,表示长度大于6小于10
5、widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "密码"}, render_value=True),自定义的插件,加入html的css样式
6、validators=[RegexValidator(r'^1[358]\d{9}$', '手机格式错误'), ],正则表达式
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
7、help_text="填入0-100整数表示百分比,例如:90,表示90%",模板的提示
8、
5、注意事项
1、校验通过的字段才会在self.cleaned_data,
2、clean报错,self.add_error(none,"error")
取值,
python中:form.errors.__all__.0
模板语言中: form.non_field_errors() <==> form.errors.__all__
6、form.errors是一个dict对象,里面有很多方式,默认是ul>li
7、validators=[RegexValidator(r'^1[358]\d{9}$', '手机格式错误'), ],正则表达式
二、ModelForm组件
1、modelform组件由于对单表的操作
class LevelModelForm(forms.ModelForm):
class Meta:
model = models.Level
fields = ['title', 'percent']
1、forms.ModelForm返回self.fields里面是字典{"title":"xxx","percent":"xxxxx"}
2、只会生成filds里面的字段
3、也可以对生成的字段进行重写
4、生成的字段是根据数据库的类型生成
5、widet里面默认的是inputtext类型
2、ModelForm提供的功能
1、不编写字段,直接引用Model字段【优秀】
1、字段选择分为三类: fields = "__all__",exclude = ['active'],fields = ['title', 'percent']
class LevelModelForm(forms.ModelForm):
class Meta:
model = models.Level
fields = ['title', 'percent']
fields = "__all__"
exclude = ['active']
class LevelModelForm(BootStrapForm, forms.ModelForm):
xxx = forms.CharField(label='xxx')
class Meta:
model = models.Level
# fields = "__all__"
# exclude = ['active']
fields = ['title', 'xxx', 'percent', ]
class LevelModelForm(BootStrapForm, forms.ModelForm):
title = forms.ChoiceField(label='xxx', choices=((1, "xxx"), (2, "xxxxxx")))
class Meta:
model = models.Level
# fields = "__all__"
# exclude = ['active']
fields = ['title', 'percent', ]
2、生成HTML标签 + 插件 + 和 参数的配置,基于BootStrap样式优化
from django.shortcuts import render, redirect
from web import models
from django import forms
from django.urls import reverse
class BootStrapForm:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# {'title':对象,"percent":对象}
for name, field in self.fields.items():
field.widget.attrs['class'] = "form-control"
field.widget.attrs['placeholder'] = "请输入{}".format(field.label)
class LevelForm(BootStrapForm, forms.Form):
title = forms.CharField(
label="标题",
required=True,
)
percent = forms.CharField(
label="折扣",
required=True,
help_text="填入0-100整数表示百分比,例如:90,表示90%"
)
class LevelModelForm(BootStrapForm, forms.ModelForm):
class Meta:
model = models.Level
fields = ['title', 'percent']
1、用到super继承关系,super是按照类的继承关系从下往上找
2、moder.form执行完会返回一个fields的字典,包括所有的字段:对象
3、表单的验证
1、和form验证一样
class LevelModelForm(BootStrapForm, forms.ModelForm):
title = forms.CharField(validators=[])
class Meta:
model = models.Level
fields = ['title', 'percent', ]
def clean_percent(self):
value = self.cleaned_data['percent']
return value
4、保存(新增、更新,多于或少于生产字段)
1、增加(基于save)
form = LevelModelForm(data=request.POST)
form.save()
2、更新(基于save)
#需要传入从数据库获取的对象
form = LevelModelForm(data=request.POST,instance=对象)
form.save()
3、自己增加值(生成的字段小于数据库必填的数据)
form = LevelModelForm(data=request.POST) # 或有 ,install=对象
form.instance.percent = 10#(自己增加值)
form.save()
4、生成的字段大于数据库必填的数据(和数据库的字段匹配的添加,不匹配的数据不管)
class LevelModelForm(BootStrapForm, forms.ModelForm):
confirm_percent = forms.CharField(label="确认")
class Meta:
model = models.Level
fields = ['title', 'percent']
def level_add(request):
if request.method == "GET":
form = LevelModelForm()
return render(request, 'form.html', {"form": form})
form = LevelModelForm(data=request.POST)
if not form.is_valid():
return render(request, 'form.html', {"form": form})
# {'title': '1', 'percent': 2, 'confirm_percent': '3'}
print(form.cleaned_data)
# form.instance.percent = 10
form.save()
return redirect(reverse('level_list'))
三、super关键字
根据类的MRO(类的继承关系)顺序,从下到上去找。
扩展:Python中的类的继承关系是通过 c3算法 计算出来。
四、BootStrap样式优化
思考:无论在使用Form和ModelForm时,想要让页面好看,就需要将每个字段的插件中给他设置form-control样式。
1、forms.Form:
class LevelForm(forms.Form):
title = forms.CharField(
label="标题",
required=True,
# widget=forms.TextInput(attrs={"class": "form-control", 'placeholder': "请输入标题"}),
)
percent = forms.CharField(
label="折扣",
required=True,
help_text="填入0-100整数表示百分比,例如:90,表示90%"
)
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
# {'title':对象,"percent":对象}
for name,field in self.fields.items():
field.widget.attrs['class'] = "form-control"
field.widget.attrs['placeholder'] = "请输入{}".format(field.label)
2、forms.ModelForm:
class LevelModelForm(forms.ModelForm):
class Meta:
model = models.Level
fields = ['title', 'percent']
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
# {'title':对象,"percent":对象}
for name,field in self.fields.items():
field.widget.attrs['class'] = "form-control"
field.widget.attrs['placeholder'] = "请输入{}".format(field.label)
3、super关键字
根据类的MRO(类的继承关系)顺序,从下到上去找。
4、BootStrap样式优化
from django.shortcuts import render, redirect
from web import models
from django import forms
from django.urls import reverse
class BootStrapForm:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# {'title':对象,"percent":对象}
for name, field in self.fields.items():
field.widget.attrs['class'] = "form-control"
field.widget.attrs['placeholder'] = "请输入{}".format(field.label)
class LevelForm(BootStrapForm, forms.Form):
title = forms.CharField(
label="标题",
required=True,
)
percent = forms.CharField(
label="折扣",
required=True,
help_text="填入0-100整数表示百分比,例如:90,表示90%"
)
class LevelModelForm(BootStrapForm, forms.ModelForm):
class Meta:
model = models.Level
fields = ['title', 'percent']
五、form或modelForm显示默认值
1、form显示默认值
form = LevelForm(initial={'title': "xxx"})
2、modelform显示默认值
level_object = models.Level.objects.filter(id=pk).first()
form = LevelModelForm(instance=level_object)
六、modelForm数据关联和校验方式
1、利用modelForm来实现关联数据(关联字段的跨表)
1、方式一:数据库表结构
level = models.ForeignKey(verbose_name="级别", to="Level", on_delete=models.CASCADE, limit_choices_to={'active': 1})
2、方式二:bootstrapt样式化(self.fields['level'].queryset对象)
#1、BootStrapForm样式
class BootStrapForm:
exclude_filed_list = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# {'title':对象,"percent":对象}
for name, field in self.fields.items():
if name in self.exclude_filed_list:
continue
field.widget.attrs['class'] = "form-control"
field.widget.attrs['placeholder'] = "请输入{}".format(field.label)
2、modelforms类
class CustomerModelForm(BootStrapForm, forms.ModelForm):
exclude_filed_list = ['level']
confirm_password = forms.CharField(
label="重复密码",
widget=forms.PasswordInput(render_value=True)
)
class Meta:
model = models.Customer
fields = ["username", 'mobile', 'password', 'confirm_password', 'level']
widgets = {
'password': forms.PasswordInput(render_value=True),
'level': forms.RadioSelect(attrs={'class': "form-radio"})
}
def __init__(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
# 此处可能用到 request
self.fields['level'].queryset = models.Level.objects.filter(active=1)
2、modelform校验方式
1、数据库表结构校验
mobile = models.CharField(verbose_name="手机号", max_length=11,
db_index=True, validators=[RegexValidator(r'^\d{11}$', '手机号格式错误'), ],)
2、modelform校验
和form校验一样
七、modelform自定义插件补充
针对自定义插件:
class ChargeModelForm(BootStrapForm, forms.ModelForm):
# 静态变量
charge_type = forms.TypedChoiceField(
label="类型",
choices=[(1, "充值"), (2, "扣款")], # 只适合固定的数据,不适合去数据表中数据
coerce=int
)
class Meta:
model = models.TransactionRecord
fields = ['charge_type', 'amount']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# self.fields['charge_type'].choices = [(1, "充值"), (2, "扣款")] # 只适合固定的数据,不适合去数据表中数据
# self.fields['creator'].choices = models.Administrator.objects.filter(id__gt=1).values_list("id", 'username')