Django 自訂 forms 欄位 HTML
分類
說明
本篇將示範如何自訂 forms 欄位生成的 HTML。
前置作業
範例會使用 bootstrap class,你需要先安裝 bootstrap,否則修改完之後不會看到效果,你也可以使用自訂的 class 或修改其他內容。
為了方便說明假設你已經配置好 app 名字為 my_app。
目標
示範修改 ImageField 欄位。
備註:/ 代表從專案目錄開始
自訂 ClearableFileInput 類別
我將自訂類別存放在 /common/forms/。
對於 ImageField 或其他的欄位要繼承哪個類別可以這樣看。
# 查看 ImageField
from django.forms import ImageField
# 再查看 FileField
class ImageField(FileField):
# 找到 widget 使用 ClearableFileInput
class FileField(Field):
    widget = ClearableFileInput
之後我們將修改 widget,所以找到 ClearableFileInput 就可以了。
繼承 ClearableFileInput 類別,修改 template_name 的路徑,使用自訂的模板,當然你還可以修改方法,自訂方法,查看 ClearableFileInput 就能了解更多。
/common/forms/bootstrap_clearable_file_input.py
"""bootstrap clearable file input render"""
from django.forms import ClearableFileInput
class BootstrapClearableFileInput(ClearableFileInput):
    """bootstrap clearable file input render"""
    template_name = "common/forms/widgets/bootstrap_clearable_file_input.html"
有時候可以直接修改 attrs 就不用自訂模板了,例如:修改 get_context(self, name, value, attrs)。
    # 略
    def get_context(self, name, value, attrs):
        attrs = {**(attrs or {})}
        # 自訂內容
        return super().get_context(name, value, attrs)
自訂模板
先複製原本的模板內容再進行調整,例如 ClearableFileInput 原本的 template_name = "django/forms/widgets/clearable_file_input.html" 先到 Django 套件的 templates 找到這個檔案,大概位置在 python3/site-packages/django/forms/templates/django/forms/widgets/clearable_file_input.html。
我加了 span 標籤和修改 input class 如下。
/common/templates/common/forms/widgets/bootstrap_clearable_file_input.html
{% comment %} clearable file input {% endcomment %}
{% if widget.is_initial %}
    {{ widget.initial_text }}: <a href="{{ widget.value.url }}">{{ widget.value }}</a>
    {% if not widget.required %}
        <span class="form-check form-check-inline">
            <input type="checkbox"
                   name="{{ widget.checkbox_name }}"
                   id="{{ widget.checkbox_id }}"
                   class="form-check-input"
                   {% if widget.attrs.disabled %}disabled{% endif %}>
            <label for="{{ widget.checkbox_id }}" class="form-check-label">{{ widget.clear_checkbox_label }}</label>
        </span>
    {% endif %}
    <br>
    {{ widget.input_text }}:
{% endif %}
<input type="{{ widget.type }}"
       name="{{ widget.name }}"
       {% include "django/forms/widgets/attrs.html" %}>
表單
修改欄位的 widgets
forms.py
from django.forms import ModelForm
from common.forms.bootstrap_clearable_file_input import BootstrapClearableFileInput
from my_app.models import Article
class ArticleForm(ModelForm):
    """文章表單"""
    class Meta:
        model = Article
        fields = ["title", "content", "image"]
        # 略
        widgets = {
            "image": BootstrapClearableFileInput,
        }
一般的 forms 欄位修改 widget 範例。
forms.py
from django import forms
class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)
配置
common 是我自訂的,你不一定要放在 common 資料夾裡面,其他照著設定就行了。
settings.py
import django
INSTALLED_APPS = [
    # 略
    "django.forms",
]
FORM_RENDERER = "django.forms.renderers.TemplatesSetting"
TEMPLATES = [
    {
        # 略
        "DIRS": [
            BASE_DIR / "common" / "templates",
            django.__path__[0] + "/forms/templates",
        ],
        # 略
    }
]
結論
這次水沒有很深,但也夠嗆了,沒事就使用預設欄位就好。
參考
一杯咖啡的力量,勝過千言萬語的感謝。
支持我一杯咖啡,讓我繼續創作優質內容,與您分享更多知識與樂趣!