标签:表达 widgets response lis ios 子函数 插入 地方 enc
# 查看所有字段可点进forms中,fields里面是所有字段,widgets是所有插件
CharField # 生成input框,默认文本输入框
ChoiceField # 选择框,默认是select单选下拉框
MultipleChoiceField # 多选框,默认是select下拉框。里面是选择的内容
注:想更改可以用已经写好的字段,也可以直接改widget
如:email = forms.CharField(label='邮箱',widget=EmailInput)将文本输入框改成了邮箱输入框。
required=True, 是否允许为空
widget=None, HTML插件,改变input框中格式,如:从文本变成email
label=None, 用于生成Label标签或显示内容
initial=None, 初始值,默认值,默认填在input框中
error_messages=None, 修改错误信息显示内容 {'required': '不能为空', 'invalid': '格式错误'}
键是对应的参数,值是想要显示的错误信息内容
validators=[], 自定义验证规则
disabled=False, 是否可以编辑
min_length: 设置最小长度
# widget=forms.PasswordInput() 设置成密文
# widget=forms.RadioSelect() 设置单选框
# widget=CheckboxInput() 设置input选择框,应用:记住密码
# widget=forms.CheckboxSelectMultiple() 设置多选框
注:模板中使用方法都是不加括号的。
{{ form_obj.as_p }} __> 生产一个个P标签 input label,实际使用不使用这个
{{ form_obj.errors }} ——》 form表单中所有字段的错误
{{ form_obj.username }} ——》 一个字段对应的input框,实际使用中
{{ form_obj.username.label }} ——》 该字段的中文提示
{{ form_obj.username.id_for_label }} ——》 该字段input框的id
{{ form_obj.username.errors }} ——》 该字段的所有的错误
{{ form_obj.username.errors.0 }} ——》 该字段的第一个错误的错误
{{ form_obj.non_field_errors.0 }} ---》 所有字段以外的错误
views.py
先定义一个RegForm类:
from django import forms
class RegForm(forms.Form)
username = forms.CharField(label='用户名',min_length=6)
pwd = forms.CharField(label='密码',widget=forms.PasswordInput) # widget设置密文
hobby = forms.MultipleChoiceField(choices=((1,'篮球'),(2,'足球'),(3,'双色球')))
## 使用get_字段名_display()方法,获取到choices后面显示的结果。
error_messages={
'required': '用户名是必填项',
'min_length': '用户名长度不能小于6位'
} # form组件默认错误提示都是英文,可以通过这种方式自定义成中文。
# min_length: 设置最小长度
# widget=forms.PasswordInput 设置成密文
# choice=((),())
再写一个视图函数
# 使用form组件实现注册方式
def register(request):
form_obj = RegForm()
if request.method == 'POST':
form_obj = RegForm(data=request.POST)
if form_obj.is_valid(): # 对数据进行校验,返回值是True或False
# 校验成功 把数据插入数据中
# models.UserProfile.objects.create(**form_obj.cleaned_data)
return HttpResponse('注册成功')
return render(request,'register.html',{'form_obj':form_obj})
html文件
<form action="" method="post" novalidate>
{% csrf_token %}
<p>
<label for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
{{ form_obj.username }}
{{ form_obj.username.errors.0 }}
</p>
</form>
如果部分数据需要从数据库中获取,那么数据需要随时更新,但是py文件并不是每次都加载,只加载一次放到内存中,py文件从上到下加载,RegForm()这个类中的内容只加载一次存到内存中,视图函数使用时,只是实例化这个类,并不会重新加载。只有当程序重启时才会重新加载,那么数据库中如果更新,则无法获取到新的数据。想让数据时时更新
# 手动定义一个__init__,只要类实例化就会执行一次__init__,时时查询
def __init__(self,*args,**kwargs):
super(RegForm,self).__init__(*args,**kwargs) # 继承父类,执行父类方法,否则会丢失功能
self.fields['hobby'].choices = models.Hobby.objects.values_list('id','name')
# values_list 由id,name组成的一个个元组的列表
# self.fields会拿到RegForm类中所有字段的对象,是一个有序字典,如下
OrderedDict([
('username', <django.forms.fields.CharField object at 0x0000000004108C18>),
('pwd', <django.forms.fields.CharField object at 0x0000000004108F60>),
('hobby', <django.forms.fields.CharField object at 0x0000000004108978>)
])
# 直接以下面方法写
hobby = forms.ModelMultipleChoiceField( # 多选框
queryset=models.Hobby.objects.all(),
)
class RegForm(forms.Form): # 需要一个一个字段写
username = forms.CharField(
label='用户名',
min_length=6,
initial='张三',
required=True,
validators=[checkname], # 列表中填写自定义的校验器,会把字段的值自动传给校验器进行校验
widget = forms.TextInput(attrs={...})
# attrs定义标签属性
error_messages={
'required': '用户名是必填项',
'min_length': '用户名长度不能小于6位'
}
)
gender = forms.ChoiceField(choices=[(1,'男'),(2,'女')]) # 单选
# 方式一:要定义一个函数
from django.core.exceptions import ValidationError
def checkname(value): # 传的值就是字段要提交的数据,对value进行校验就行了
# 通过校验规则 不做任何操作
# 不通过校验规则 抛出异常
if 'alex' in value:
raise ValidationError('不符合社会主义核心价值观')
# 方式二:内置的校验器
from django.core.validators import RegexValidator # 导入模块,正则校验
# validators还有一些其他格式的校验器
class RegForm(forms.Form):
phone = forms.CharField(
validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式不正确')]
)
# RegexValidator(),第一个参数写正则表达式,第二个参数写错误提示
什么叫钩子:
其主要思想是提前在可能增加功能的地方埋好(预设)一个钩子,这个钩子并没有实际的意义,当我们需要重新修改或者增加这个地方的逻辑的时候,把扩展的类或者方法挂载到这个点即可。
局部钩子
def clean_username(self):
# 局部钩子,对单独一个字段进行校验
# 通过校验规则 必须返回当前字段的值
# 不通过校验规则 抛出异常
v = self.cleaned_data.get('username') # 能走到局部钩子,cleaned_data中就有值了,不然无法通过内置校验器和自定义校验器
if 'alex' in v:
raise ValidationError('不符合社会主义核心价值观')
else:
return v
全局钩子
def clean(self):
# 全局钩子,对多个字段进行校验
# 通过校验规则 必须返回当前所有字段的值
# 不通过校验规则 抛出异常 '__all__'
# 如果重写clean方法,必须写_validate_unique = True,不然不会校验字段的唯一性
# 会检查model中的unique的限制
self._validate_unique = True
pwd = self.cleaned_data.get('pwd')
re_pwd = self.cleaned_data.get('re_pwd')
if pwd == re_pwd:
return self.cleaned_data
else:
self.add_error('re_pwd','两次密码不一致!!!!!') # 将错误信息添加到错误字典
raise ValidationError('两次密码不一致')
#### is_valid的流程:执行is_valid()的流程
1.先执行full_clean()的方法:
- 定义错误字典
- 定义存放清洗数据的字典
2.执行_clean_fields方法:
- 循环所有的字段
- 获取当前的值
- 进行校验 ( 内置校验规则 自定义校验器)
1. 通过校验
self.cleaned_data[name] = value
- 如果有局部钩子,执行进行校验:
- 通过校验——》 self.cleaned_data[name] = value
- 不通过校验——》
self._errors 添加当前字段的错误 并且 self.cleaned_data中当前字段的值删除掉
2. 没有通过校验
self._errors 添加当前字段的错误
3.执行全局钩子clean方法
# 最终的判断就是错误字典中是否有值
使用方法
########form组件使用步骤############
1.先导入forms模块
2.写类,继承forms.ModelForm
3.在类中再写元类Meta
4.在Meta中写字段model,代表根据哪个Model生字段,---》model = models.UserProfile
# UserProfile是创建表的类名
5.字段fields,表示生成此Model中的哪些字段。__all__表示所有字段都生成,fields = '__all__';
单独生成某几个字段
6.如果表中没有的字段,可在类下创建
###########代码如下################
from django import forms
from app名称 import models
from django.core.exceptions import ValidationError
class RegForm(forms.ModelForm)
# 与继承forms.Form的区别在于,forms.Form要在类中写每一个需要创建的input框
# forms.ModelForm不需要每个都写,会根据某一个Model具体的生成每一个字段
password = forms.CharField(widget=forms.PasswordIput('placeholder':'您的密码')) # 重写样式
re_password = forms.CharField(widget=forms.PasswordIput('placeholder':'再次输入密码'))
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
# 限制当前新增客户为当前访问客户
self.fields['customer'].choices = [(self.instance.customer.pk,self.instance.customer)]
# 表中没有的字段可在Meta类下创建
class Meta:
model = models.UserProfile # 根据哪个Model生成字段,UserProfile是创建表的类名
fields = '__all__' # 生成表中的哪些字段,'__all__'是生成所有的
# 填写指定字段['username','password']
exclud = ['is_active'] # 排除is_active字段
widgets = { # 字典内写上指定字段的名字
'username':forms.TextInput(attrs={'placeholder':'您的用户名','autocomplete':'off'})
}
# autocomplete表示填写记录
# 可以对表中的所有字段样式,进行修改
# attrs中写想要更改的相关属性
error.messages = { # 错误信息
'username':{
'required':'必填' # 必填
'invalid':'请输入正确邮箱地址' # 格式错误
}
}
# 在settings配置文件中将LANGUAGE_CODE = 'zh-Hans'
def clean(self):
password = self.cleaned_data.get('password',"")
# 当都不填时会返回None在加密时报错,所以让他获取不到password时获取一个空字符串
re_password = self.cleaned_data.get('re_password',"")
if password == re_password:
# 对密码进行加密
md5 = hashlib.md5()
md5.update(password.encode('utf-8'))
self.cleaned_data['password'] = md5.hexdigest()
return self.cleaned_data
else:
self.add_error('re_password', '两次密码不一致')
raise ValidationError('两次密码不一致!!')
######视图函数######
def reg(request): # 视图函数
form_obj = RegForm()
if request.method == 'POST':
form_obj = RegForm(request.POST)
if form_obj.is_valid():
form_obj.save()
return redirect(reverse('login'))
return render(request,'reg.html',{'form_obj':form_obj})
#######模板语法#######
<form action='' ,method='post' novalidate>
# novalidate 不在前端进行校验,前端写的校验会失效
{% for field in form_obj %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
<label {% if not field.field.required %} style="color: #777777" {% endif %} for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{ field.label }}</label>
<div class="col-sm-8">
{{ field }}
<span class="help-block">{{ field.errors.0 }}</span>
</div>
</div>
{% endfor %}
{{ form_obj.errors }} ——》 form表单中所有字段的错误
{{ form_obj.username }} ——》 一个字段对应的input框,一般使用这个一个个input创建
{{ form_obj.username.label }} ——》 该字段的中文提示
{{ form_obj.username.id_for_label }} ——》 该字段input框的id
{{ form_obj.username.errors }} ——》 该字段的所有的错误
{{ form_obj.username.errors.0 }} ——》 该字段的第一个错误的错误
{{ form_obj.non_filed_errors }} ——》 # __all__的错误,不限于表单中
</form>
更改input框的中文名显示方式
1.创建表时填写verbose_name属性,值为想要显示的中文名
2.在常见input框时有label标签,可以显示中文
modelformset_factory
会先创建一个类,参数有model,Form类,extra
ModelFormSet = modelformset_factory(models.StudyRecord, StudyRecordForm, extra=0)
def study_record_list(request, course_record_id):
ModelFormSet = modelformset_factory(
models.StudyRecord, StudyRecordForm, extra=0)
form_set_obj = ModelFormSet(queryset=models.StudyRecord.objects.filter
(course_record_id=course_record_id))
if request.method == 'POST':
form_set_obj = ModelFormSet(queryset=models.StudyRecord.objects.filter
(course_record_id=course_record_id),data=request.POST)
if form_set_obj.is_valid():
form_set_obj.save()
return HttpResponse('保存成功')
return render(request, 'teacher/study_record_list.html', {'form_set_obj': form_set_obj})
模板中
<!--文本不可修改的内容用该方式取-->
<td>{{ form.instance.student }}</td>
// form.instance 是一个对象
// form.instance.student 通过对象拿到其中的字段值
<!--在模板中使用-->
在form标签下必须添加如下内容,固定写法
{{ form_set_obj.management_form }} <!--会生成4个隐藏标签-->
<input type="hidden" name="form-TOTAL_FORMS" value="2" id="id_form-TOTAL_FORMS">
<input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS">
<input type="hidden" name="form-MIN_NUM_FORMS" value="0" id="id_form-MIN_NUM_FORMS">
<input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS">
在循环创建form表单时,再循环下加{{ form.id }},用来标识form表单,目的找对应的对象,生成隐藏input标签
<input type="hidden" name="form-1-id" value="2" id="id_form-1-id">
<!--代码示例-->
<form action="" method="post">
{% csrf_token %}
{{ form_set_obj.management_form }}
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>序号</th>
<th>学生</th>
<th>考勤</th>
<th>成绩</th>
<th>作业批语</th>
</tr>
</thead>
<tbody>
{% for form in form_set_obj %}
<tr>
{{ form.id }}
<td>{{ forloop.counter }}</td>
<td>{{ form.instance.student }}</td>
<td>{{ form.attendance }}</td>
<td>{{ form.score }}</td>
<td>{{ form.homework_note }}</td>
<td class="hidden">{{ form.student }}</td>
<td class="hidden">{{ form.course_record }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button class="btn btn-primary">保存</button>
</form>
标签:表达 widgets response lis ios 子函数 插入 地方 enc
原文地址:https://www.cnblogs.com/liuweida/p/12303066.html