正在进入ing...

Django纯后端使用layui渲染美化表单

发布时间:2021-12-29 浏览量: 805 文章分类: python

由于对于前端的系统组件类的东西使用一直不是很好,日常还是偏向于使用bootstarplayui+jQuery一把梭一些小项目。在使用Django的时候通就遇到了渲染界面美化的问题。所以备忘一下。

背景: 用户提交表单,表单是通过djangomodels+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_passwordattrs里面的参数,但是如果每个都这么添加其实也是一件很麻烦的事情,毕竟如果字段过多,每个都要去设置classplaceholder,所以可以通过重写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 }
        )