<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Loading

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

      前言

      歐克,繼續來寫這個中臺項目衍生出來的系列文章

      今天介紹一個可以美化界面的庫

      Django 開發講究個快,天下武功,唯快不破

      forms 功能自然是要用的,自帶表單 UI 生成和驗證,實現 demo 時非常方便

      之前我在 DjangoStarter 框架里已經封裝了一套 forms 行為和樣式了,在 src/django_starter/contrib/forms

      這套已經不錯了,也是用 TailwindCSS 來實現樣式,挺好看的

      不過在開發中臺項目的時候,我發現了 django-crispy-forms 這個庫,提供了更多美化表單 UI 的靈活性。

      DjangoStarter里的實現

      先來看看 DjangoStarter 框架的實現

       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

      {% 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

      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

      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

      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 是咋實現的

      安裝后,簡單配置下就能用了

      使用起來類似下面這樣

      {% 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>
      

      安裝

      安裝依賴

      pdm install django-crispy-forms
      

      然后添加到

      INSTALLED_APPS = (
          ...
          'crispy_forms',
      )
      

      Template packs

      然后還得安裝 Template packs

      不然只是個空殼

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

      好在社區也提供了不少,這里我只關注 Tailwind CSS 的庫,名字是 crispy-tailwind

      pdm add crispy-tailwind
      

      其他 UI 庫還有很多,感興趣的同學可以在官網看到: https://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs

      這個同樣也得添加進去

      INSTALLED_APPS = (
          ...
          'crispy_forms',
          'crispy_tailwind',
      )
      

      配置

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

      src/config/settings/components/crispy_forms.py

      CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind"
      CRISPY_TEMPLATE_PACK = "tailwind"
      

      使用

      最簡單的用法是只修改模板文件

      {% 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 的,感覺挺有意思的,有時間可以試試看

      posted @ 2025-07-19 14:33  程序設計實驗室  閱讀(394)  評論(2)    收藏  舉報
      主站蜘蛛池模板: 男女猛烈激情xx00免费视频| 黄色A级国产免费大片视频| 99久久激情国产精品| 亚洲欧美在线一区中文字幕| 欧美成人精品手机在线| 久久被窝亚洲精品爽爽爽| 欧美精品人人做人人爱视频| 91精品蜜臀国产综合久久| 国模少妇无码一区二区三区 | 九九热在线视频观看最新| 精品国产成人国产在线视| 成在线人永久免费视频播放| 国产成人a∨激情视频厨房| 亚洲国产精品黄在线观看| 国内精品久久久久电影院| 亚洲精品色国语对白在线| 亚洲美女高潮不断亚洲| 一区二区福利在线视频| 99在线精品视频观看免费| 久99久热只有精品国产99| 抚宁县| 国产又爽又黄又刺激的视频| 亚洲一区二区中文字幕| 动漫精品专区一区二区三区| 亚洲春色在线视频| 日韩深夜视频在线观看| 日本黄漫动漫在线观看视频| 无套内谢少妇一二三四| 亚洲国产在一区二区三区| 国产精品成人va在线播放| 国产视频一区二区三区麻豆| 国产精品美女久久久久久麻豆| 国产69久久精品成人看| 老色99久久九九爱精品| 亚洲人成网站77777在线观看| 台前县| 麻豆a级片| 97久久精品无码一区二区| 国产精品天天看天天狠| 久久精品国产国产精品四凭| 国产小受被做到哭咬床单GV|