Django 自訂 forms 欄位 HTML


建立時間: 2023年8月18日 22:49
更新時間: 2023年11月8日 11:37

說明

本篇將示範如何自訂 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",
        ],
        # 略
    }
]

結論

這次水沒有很深,但也夠嗆了,沒事就使用預設欄位就好。

參考

觀看次數: 468
customdjangofieldwidget自訂
按讚追蹤 Enjoy 軟體 Facebook 粉絲專頁
每週分享資訊技術

一杯咖啡的力量,勝過千言萬語的感謝。

支持我一杯咖啡,讓我繼續創作優質內容,與您分享更多知識與樂趣!