ModelForm 或者 Form组件的作用:
模板时间格式化显示
{{item.event_start|date:“Y-m-d H:i:s”}}
{{bio|truncatewords:“30”}}
{{my_list|first|upper}}
{{name|lower}}
obj.create_time.strftime("%Y-%m-%d %H:%M:%S"))
()
的, 模板会自动帮我们添加.models中,建立自定义枚举类的约束到数据库
gender_choices = (
(1, "男"),
(2, "女"),
)
gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
python中获取Model中自定义的Enum名称,调用对应的get_gender_display()
方法
obj.get_gender_display()
模板中调用该方法获取Enum名称时,不可以加()
{{ i.get_gender_display }}
本节中包含ModelForm字段中批量添加BootStrap5.1的实现,可以单独提取出来封装成一个类,配合BootStrap5.1一起使用
views中
class UserModelForm(ModelForm):
# 自定义校验规则, 不自定义会启用默认校验规则
name = forms.CharField(min_length=3, label="用户名")
# password = forms.CharField(label="密码", validators='正则')
# 删除时间输入框的浏览器自动提示 方式1
# create_time = forms.DateTimeField(label="入职时间", widget=forms.DateTimeInput(attrs={
# 'autocomplete': 'off'
# }))
# 自动生成html页面标签
class Meta:
model = UserInfo
fields = ["name", "password", 'age', "account", "create_time", "gender", "depart"]
# 循环找到所有的控件, 添加类名
def __init__(self, *args, **kwargs):
super(UserModelForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
# name 字段名
# field 字段对应的对象
# 字段中有属性,保留原来的属性,没有属性,才增加
if field.widget.attrs:
field.widget.attrs['class'] = 'form-control'
field.widget.attrs['placeholder'] = field.label
else:
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
# 如果是时间输入,屏蔽掉浏览器自带的输入提示,方便DateTimePicker的显示
if name == "create_time":
field.widget.attrs['autocomplete'] = 'off'
def user_mode_form_add(request):
""" 添加用户 (ModelForm版本)"""
form = UserModelForm()
return render(request, "app01/user_model_form_add.html", locals())
def user_mode_form_add(request):
# 用户POST提交数据,数据校验
form = UserModelForm(data=request.POST)
if form.is_valid():
# 校验成功,入库
# print(form.cleaned_data)
# 自动入库
form.save()
return redirect("/user/list/")
# 验证失败 ,页面显示错误信息
print(form.errors)
return render(request, "app01/user_model_form_add.html", locals())
templates中
其中DateTimePicker不是关注点, 文中忽略
模板中直接调用form中的field,对于字段是外键的,如果不做任何处理,返回的是对象类型.
<form method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="mb-3">
{# ModelForm类自动生成面页标签和面页控件 #}
<label for="name" class="form-label">{{ field.label }}label>
{{ field }}
<span style="color:red;">{{ field.errors.0 }} span>{# [error1 error2] #}
div>
{% endfor %}
<button type="submit" class="btn btn-primary btn-sm">保存button>
form>
models中
class Department(models.Model):
# 部门表
title = models.CharField(verbose_name="部门名称", max_length=32)
def __str__(self):
# 解决ModelForm的外键引用返回对象的问题.
return self.title
对于密码输入框的加密处理
自定义一个模块
用md5加密,再加上django自带的盐
import hashlib
from django.conf import settings
def md5(data_string):
salt = settings.SECRET_KEY
obj = hashlib.md5(salt.encode("utf-8"))
obj.update(data_string.encode("utf-8"))
return obj.hexdigest()
在views中
class AdminModelForm(BootStrapModelForm):
# 数据表中没有,但是我们需要添加一个字段的处理方式
confirm_password = forms.CharField(
label="确认密码",
# render_value=True,密码错误的时候页不会清空输入框
widget=forms.PasswordInput(render_value=True))
class Meta:
model = Admin
fields = "__all__"
widgets = {
"password": forms.PasswordInput
}
# 定义钩子方法 在数据提交到数据库前的操作
def clean_password(self):
pwd = self.cleaned_data.get("password")
return md5(pwd)
# 勾到confirm_password字段上
def clean_confirm_password(self):
# print(self.cleaned_data)
pwd = self.cleaned_data.get("password")
confirm = self.cleaned_data.get("confirm_password")
confirm = md5(confirm)
if pwd != confirm:
# 抛自定义的异常
raise ValidationError("密码不一致")
# 如果不抛异常,就会直接return confirm这个值, 并且通过form.save()入库
return confirm
在做密码验证的时候,如果用户名或者密码错误,可以通过向form中主动添加错误的方式来提示用户
在views中
exists = Admin.objects.filter(**form.cleaned_data).exists()
if exists:
return redirect("/admin/list/")
else:
# 主动在form中显示一个错误
form.add_error("password", "用户名或者密码错误")
return render(request, "app01/login.html", locals())
在views中,函数前添加一个装饰器
@csrf_exempt
def task_ajax(request):
print(request.POST)
return HttpResponse("不刷页面发送请求")