Django纯后端使用layui渲染美化表单
由于对于前端的系统组件类的东西使用一直不是很好,日常还是偏向于使用bootstarp
、layui
+jQuery
一把梭一些小项目。在使用Django
的时候通就遇到了渲染界面美化的问题。所以备忘一下。
背景:
用户提交表单,表单是通过django
的models
+forms
生成,前端使用layui
,希望可以在生成的同时根据不同的类型直接进行渲染。
备忘:
models.py
class UserInfo(models.Model):
username = models.CharField(verbose_name='用户名',max_length=32)
email = models.EmailField(verbose_name='邮箱')
phone = models.CharField(verbose_name='手机号',max_length=32)
password = models.CharField(verbose_name='密码',max_length=32)
forms.py
class RegisterModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = '__all__'
现在上面用的是一个最为简单的模型,如果单纯使用在页面渲染,样子就是下面这样,在开始处理之前,我逐步记录一下自己的操作步骤。
修改前端展示的表单字段名
RegisterModelForm
是一个表单类,他是支持自定义的。比如
class RegisterModelForm(forms.ModelForm):
phone = forms.EmailField(label="手机号码")
class Meta:
model = models.UserInfo
fields = '__all__'
注意上面的phone = forms.EmailField(label="手机号码")
如果我增加了自己定义的label
,那么html
页面的表单标题就会以我这个为准,而不是models
里面的verbose_name
了。所以如果后续觉得models
里面定义的名字不太适合直接展示到前端,可以用这种方式修改在前端的展示。
给表单增加自定义正则
很多时候我们需要对表单的内容进行验证(虽然前端也会验证,但是我们如果没做前后端分离的话,这个工作还是要我们来自己实现),我们需要借助Django
提供的from django.core.validators import RegexValidator
方法
from django.core.validators import RegexValidator
class RegisterModelForm(forms.ModelForm):
phone = forms.EmailField(label="手机号码",validators=[RegexValidator(r'^(1[3|4|5|6|&|8|9])\d{9}$','手机号格式错误'),])
class Meta:
model = models.UserInfo
fields = '__all__'
这里需要注意validators
是一个列表,里面支持多个正则,所以你可以[(正则语句1,错误提示1),(正则语句2,错误提示2)...]
这样一直写下去。RegexValidator
接受2个参数,第一个是正则表达式,第二个是错误提示。
widget
修改样式插件
如果按照上面的例子跑起来会发现页面的密码是可见的,这就很奇怪了,正常我们输入的密码都是会被转换成*号。所以password
这个字段也需要拿出来单独重写。
class RegisterModelForm(forms.ModelForm):
phone = forms.EmailField(label="手机号码",validators=[RegexValidator(r'^(1[3|4|5|6|&|8|9])\d{9}$','手机号格式错误'),])
password = forms.CharField(label="密码",widget=forms.PasswordInput())
class Meta:
model = models.UserInfo
fields = '__all__'
增加额外的字段
比如在注册的时候,我们通常会让用户将密码输入2次,防止创建时输入错误,或者页面还需要用户输入验证码等,这些不可能都写到models
的模型中,所以相当于我们在表单中还需要增加一些自定义的字段。
class RegisterModelForm(forms.ModelForm):
phone = forms.EmailField(label="手机号码",validators=[RegexValidator(r'^(1[3|4|5|6|&|8|9])\d{9}$','手机号格式错误'),])
password = forms.CharField(label="密码",widget=forms.PasswordInput())
# 增加一个自定义需要用户重复输入的密码
confirm_password = forms.CharField(label="重复输入密码",widget=forms.PasswordInput())
class Meta:
model = models.UserInfo
fields = '__all__'
注意confirm_password
,这里需要注意的就是字段的名字不能和数据库的名字字段重复,负责会覆盖。(生成code是用一样的模式)
渲染带class
样式的表单
如果不进行任何修改,那么在页面的样式就是纯html实现的,这并不是我想要的。可以借助于attrs
来实现参数的传递渲染。
class RegisterModelForm(forms.ModelForm):
phone = forms.EmailField(label="手机号码",validators=[RegexValidator(r'^(1[3|4|5|6|&|8|9])\d{9}$','手机号格式错误'),])
password = forms.CharField(label="密码",widget=forms.PasswordInput())
confirm_password = forms.CharField(label="重复输入密码",widget=forms.PasswordInput(attrs={'class':'layui-input','placeholder':'请输入输入密码'}),)
class Meta:
model = models.UserInfo
fields = '__all__'
注意上面confirm_password
的attrs
里面的参数,但是如果每个都这么添加其实也是一件很麻烦的事情,毕竟如果字段过多,每个都要去设置class
、placeholder
,所以可以通过重写init
方法,让类来自动渲染。
class RegisterModelForm(forms.ModelForm):
phone = forms.EmailField(label="手机号码",validators=[RegexValidator(r'^(1[3|4|5|6|&|8|9])\d{9}$','手机号格式错误'),])
password = forms.CharField(label="密码",widget=forms.PasswordInput())
confirm_password = forms.CharField(label="重复输入密码",widget=forms.PasswordInput())
class Meta:
model = models.UserInfo
fields = '__all__'
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
# 循环遍历每个字段,并统一添加layui-input样式
for name,field in self.fields.items():
field.widget.attrs['class'] = 'layui-input'
field.widget.attrs['placeholder'] = f'请输入{field.label}'
同理,因为不可能整个项目只有一个form
,所以可以将init
内容做一个类,直接让后续所有使用layui
样式的form
来继承。
class LayuiForm(object):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环遍历每个字段,并统一添加layui-input样式
for name, field in self.fields.items():
field.widget.attrs['class'] = 'layui-input'
field.widget.attrs['placeholder'] = f'请输入{field.label}'
class RegisterModelForm(LayuiForm,forms.ModelForm):
phone = forms.EmailField(label="手机号码",validators=[RegexValidator(r'^(1[3|4|5|6|&|8|9])\d{9}$','手机号格式错误'),])
password = forms.CharField(label="密码",widget=forms.PasswordInput())
confirm_password = forms.CharField(label="重复输入密码",widget=forms.PasswordInput())
class Meta:
model = models.UserInfo
fields = '__all__'
支持更多layui
样式
通过上面的例子,已经可以满足各种输入框的样例了,但是实际的表单中,可能还存在下拉、文本框、开关、单选、复选等等。那这个时候,我们的样例就没办法渲染了。(毕竟只能渲染layui-input
一个样式)
钩子验证数据问题
通常用户在注册提交的数据,很多是需要经过我们的验证才可以存储或使用的。比如注册的账号、邮箱是否存在,密码是否合规等。都可以通过clean
来进行验证。而对验证错误的情况应该予以返回错误提示。首先需要引入from django.core.exceptions import ValidationError
class RegisterModelForm(LayuiForm,forms.ModelForm):
password = forms.CharField(label="密码",widget=forms.PasswordInput())
confirm_password = forms.CharField(label="重复输入密码",widget=forms.PasswordInput())
class Meta:
model = models.UserInfo
fields = '__all__'
def __init__(self,request,*args,**kwargs):
super().__init__(*args,**kwargs)
self.request = request # 将视图的request 传递到form里面
def clean_username(self):
# 效验用户名是否存在
username = self.cleaned_data['username']
# 效验数据库是否存在
exists = models.UserInfo.objects.filter(username=username).exists()
if exists:
raise ValidationError('手机号已存在')
return username
class IndexView(View):
def get(self,request,*args,**kwargs):
form = RegisterModelForm(request)
return render(
request,
'register.html',
{'form':form }
)