使用django-crispy-forms美化表单UI

前言

欧克,继续来写这个中台项目衍生出来的系列文章

今天介绍一个可以美化界面的库

Django 开发讲究个快,天下武功,唯快不破

forms 功能自然是要用的,自带表单 UI 生成和验证,实现 demo 时非常方便

之前我在 DjangoStarter 框架里已经封装了一套 forms 行为和样式了,在 src/django_starter/contrib/forms

这套已经不错了,也是用 TailwindCSS 来实现样式,挺好看的

不过在开发中台项目的时候,我发现了 django-crispy-forms 这个库,提供了更多美化表单 UI 的灵活性。

DjangoStarter里的实现

先来看看 DjangoStarter 框架的实现

php 复制代码
 forms
 ├─ widgets
 │  ├─ __init__.py
 │  ├─ multiple_file.py
 │  └─ flowbite_date_picker.py
 ├─ templates
 │  └─ django_starter
 │     └─ forms
 │        ├─ widgets
 │        └─ form_template.html
 ├─ __init__.py
 ├─ widget_classes.py
 ├─ mixins.py
 └─ base.py

template

src/django_starter/contrib/forms/templates/django_starter/forms/form_template.html

django 复制代码
{% for field in form %}
    <div>
        <label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
               for="{{ field.id_for_label }}">{{ field.label }}</label>
        {{ field }}
        <div class="mt-2 text-sm text-gray-500 dark:text-gray-200">
            {{ field.help_text }}
        </div>
        <div class="mt-2 text-sm text-red-600 dark:text-red-500">
            {{ field.errors }}
        </div>
    </div>
{% endfor %}

widgets

src/django_starter/contrib/forms/widgets/flowbite_date_picker.py

python 复制代码
from django import forms

class FlowbiteDatePickerWidget(forms.DateInput):
    template_name = 'django_starter/forms/widgets/flowbite_date_picker.html'

    def __init__(self, attrs=None, custom_class=''):
        final_attrs = {'class': custom_class}
        if attrs:
            final_attrs.update(attrs)
        super(FlowbiteDatePickerWidget, self).__init__(attrs=final_attrs)

src/django_starter/contrib/forms/widgets/multiple_file.py

python 复制代码
from django import forms


class MultipleFileInput(forms.ClearableFileInput):
    allow_multiple_selected = True


class MultipleFileField(forms.FileField):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault("widget", MultipleFileInput())
        super().__init__(*args, **kwargs)

    def clean(self, data, initial=None):
        single_file_clean = super().clean
        if isinstance(data, (list, tuple)):
            result = [single_file_clean(d, initial) for d in data]
        else:
            result = [single_file_clean(data, initial)]
        return result

forms 代码

src/django_starter/contrib/forms/mixins.py

python 复制代码
from django import forms
from .widget_classes import *


class BaseFormMixin:
    """提供表单样式的通用混入类"""

    widget_classes = {
        forms.TextInput: TEXT_INPUT_CLASS,
        forms.Textarea: TEXT_AREA_CLASS,
        forms.EmailInput: TEXT_INPUT_CLASS,
        forms.PasswordInput: PASSWORD_INPUT_CLASS,
        forms.Select: SELECT_CLASS,
        forms.DateInput: DATE_INPUT_CLASS,
        forms.NumberInput: NUMBER_INPUT_CLASS,
    }

    def apply_widget_classes(self):
        """根据widget类型为表单字段应用样式"""
        for field_name, field in self.fields.items():
            widget_class = self.widget_classes.get(type(field.widget))
            if widget_class:
                field.widget.attrs.update({'class': widget_class})

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.apply_widget_classes()

widget_classes.py 的代码就不贴了

就是 Tailwind CSS 的样式

crispy-forms 是咋实现的

安装后,简单配置下就能用了

使用起来类似下面这样

django 复制代码
{% load crispy_forms_tags %}

<div class="sm:col-span-6">
    {{ form.name|as_crispy_field }}
</div>

<div class="sm:col-span-3">
    {{ form.dvr_brand|as_crispy_field }}
</div>

<div class="sm:col-span-3">
    {{ form.dvr_model|as_crispy_field }}
</div>

<div class="sm:col-span-3">
    {{ form.dvr_ip|as_crispy_field }}
</div>

<div class="sm:col-span-3">
    {{ form.status|as_crispy_field }}
</div>

安装

安装依赖

bash 复制代码
pdm install django-crispy-forms

然后添加到

python 复制代码
INSTALLED_APPS = (
    ...
    'crispy_forms',
)

Template packs

然后还得安装 Template packs

不然只是个空壳

官方支持的只有 Bootstrap 系列,有点 out 了

好在社区也提供了不少,这里我只关注 Tailwind CSS 的库,名字是 crispy-tailwind

bash 复制代码
pdm add crispy-tailwind

其他 UI 库还有很多,感兴趣的同学可以在官网看到: https://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs

这个同样也得添加进去

python 复制代码
INSTALLED_APPS = (
    ...
    'crispy_forms',
    'crispy_tailwind',
)

配置

在配置文件里修改默认的 Template Packs

src/config/settings/components/crispy_forms.py

python 复制代码
CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind"
CRISPY_TEMPLATE_PACK = "tailwind"

使用

最简单的用法是只修改模板文件

django 复制代码
{% load crispy_forms_tags %}

<form method="post" class="my-class">
    {{ my_formset|crispy }}
</form>

目前中台项目也只用到了这个

搭配 django-select2 可以实现下拉搜索框

不过样式不好改,我折腾了一段时间也没改好,索性先不理了,反正就是一个快速实现的 DEMO

后续有需求再用 React 重写页面就行了

小结

我发现 Django 相关的技术还算是比较小众的

一般写这种文章就没什么人看

我做 Django 也好几年的时间了,框架源码看了,脚手架也搞了,用得非常顺手

虽然现在 python 的 web 框架有很多,不过所有项目最终都会成为 Django 的样子🤣

就这样吧,python 项目这一块,我还是会继续坚持 Django ,毕竟是真的方便好用

当然也不排斥尝试新的玩意,比如最近有个 Litestar 号称要干掉 FastAPI 的,感觉挺有意思的,有时间可以试试看

相关推荐
【本人】3 小时前
Django基础(四)———模板常用过滤器
后端·python·django
程序员的世界你不懂3 小时前
Django 接口自动化测试平台实现(一)
python·django·sqlite
计算机毕业设计指导12 小时前
基于 Django + 协同过滤算法的电影推荐系统设计与实现
python·算法·django
unicrom_深圳市由你创科技1 天前
使用Django框架构建Python Web应用
前端·python·django
ku_code_ku1 天前
Django由于数据库版本原因导致数据库迁移失败解决办法
后端·python·django
LuckyLay1 天前
1.2.2 高级特性详解——AI教你学Django
python·django·sqlite
【本人】1 天前
Django基础(三)———模板
后端·python·django