Django小部件覆盖模板

18

我是django的新手。

我想要创建一个自定义小部件。

forms.py:

from project.widgets import MultiChoiceFilterWidget

class CustomSearchForm(FacetedSearchForm):
    TEST_COLORS = [
        u"Blau", u"Rot", u"Gelb"
    ]

    color = forms.MultipleChoiceField(
        label=_("Color"), choices=[(x, x) for x in TEST_COLORS],
        widget=MultiChoiceFilterWidget, required=False)

widget.py:

class MultiChoiceFilterWidget(forms.widgets.CheckboxSelectMultiple):
    template_name = 'project/widgets/filter.html'
    option_template_name = 'ptoject/widgets/filter_option.html'

项目/小部件/筛选器.html:

 <h1>TEST</h1>

但它没有呈现新模板,仍然以旧方式呈现。

你能给我一些提示吗?


你在表单中如何使用这个小部件? - Daniel Roseman
@DanielRoseman 我已经编辑了我的帖子 - Flo
你正在使用哪个版本的Django? - SebCorbin
@SebCorbin 1.8.18 - Flo
你的目录结构是什么,针对于 'project/widgets/filter.html' 文件? - andilabs
你的 TEMPLATES 设置是什么? - andilabs
3个回答

38

3
这个应该是被接受的答案。有了这些设置,你只需要���小部件的.html文件放在templates/django/forms/widgets中,它就会在回退到Django默认设置之前使用这些文件。 - biodiv
2
@biodiv 一旦完成这些步骤,您可以将替换模板实例放置在项目寻找模板的任何位置。不仅是它最初寻找的镜像原始路径。 - Rob
2
不要忘记你的INSTALLED_APPS的顺序。你的带有覆盖的应用程序应该在django.forms应用程序之前。 - thelittlebug
1
以防其他人犯了和我一样的愚蠢错误...请确保将文件放在<proj>/<app>/templates/django/forms/widgets而不是<proj>/<app>/templates/<app>/django/forms/widgets - Zmaster
4
请注意,这也将影响Django管理页面。 - André Laszlo

19

Django版本小于1.11:

为了呈现不同的模板,该部件必须实现render方法:

from django.utils.safestring import mark_safe
from django.template.loader import render_to_string

class MultiChoiceFilterWidget(forms.widgets.CheckboxSelectMultiple):
    template_name = 'project/widgets/filter.html'

    def render(self, data):
        ...
        Do stuff with data
        ...
        return mark_safe(render_to_string(self.template_name))


Django 1.11版本:

渲染器文档中,我们可以找到以下内容:

Django 1.11的新功能:

在旧版本中,使用Python渲染小部件。本文档中描述的所有API都是新的。

通过查看小部件源代码,特别是查看 Input 小部件如何扩展 Widget 类,我们可以看到您只需要按照以下方式自定义小部件:

class MultiChoiceFilterWidget(forms.widgets.CheckboxSelectMultiple):
    template_name = 'project/widgets/filter.html'

这就是你已经拥有的。


如果我没记错的话,应该是 return mark_safe(render_to_string(self.template_name)) - jhrr
1
没错,@jhrr,我会修复它。 - John Moutafis

4

如果您只需要更改模板,则重新定义完整的widget没有必要。由于widget作为实例传递给字段,因此您可以实例化要使用的基本widget,然后在之后更改模板。

class CustomSearchForm(FacetedSearchForm):
TEST_COLORS = [
    u"Blau", u"Rot", u"Gelb"
]

color = forms.MultipleChoiceField(
    label=_("Color"), choices=[(x, x) for x in TEST_COLORS],
    widget=forms.widgets.CheckboxSelectMultiple, required=False)
color.widget.template_name = 'project/widgets/filter.html'
color.widget.option_template_name = 'project/widgets/filter_option.html'

如果您需要将自定义数据传递到模板中,那么您就需要创建一个自定义小部件。


这正是我所需要的,因为我不需要自定义小部件,只是想在每种情况下覆盖一些小部件模板。但是,我仍然需要使用这个答案才能找到我的自定义模板。链接 - Stephen Blair

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接