如何使用 Django 的 MultiWidget?

Posted

技术标签:

【中文标题】如何使用 Django 的 MultiWidget?【英文标题】:How do I use Django's MultiWidget? 【发布时间】:2011-03-31 12:34:28 【问题描述】:

关于此功能的文档有点缺乏。

from django import forms

class TwoInputWidget(forms.MultiWidget):
    """An example widget which concatenates two text inputs with a space"""
    def __init__(self, attrs=None):
        widgets = [forms.TextInput, forms.TextInput]

我可以看到我需要创建一个包含其他小部件列表的“小部件”属性,但之后它会得到一点福尔摩斯。

有人可以向我解释如何使用 MultiWidget 小部件吗?

【问题讨论】:

这个解决方案有点小技巧,但更符合我们期望访问模板中子字段的方式。 ***.com/questions/24866936/… 【参考方案1】:

有趣的问题,我认为可能值得在文档中多加关注。

这是来自a question I've just asked的示例:

class DateSelectorWidget(widgets.MultiWidget):
    def __init__(self, attrs=None, dt=None, mode=0):  
        if dt is not None:
            self.datepos = dt
        else:
            self.datepos = date.today()    

        # bits of python to create days, months, years
        # example below, the rest snipped for neatness.

        years = [(year, year) for year in year_digits]

        _widgets = (
            widgets.Select(attrs=attrs, choices=days), 
            widgets.Select(attrs=attrs, choices=months),
            widgets.Select(attrs=attrs, choices=years),
            )
        super(DateSelectorWidget, self).__init__(_widgets, attrs)

    def decompress(self, value):
        if value:
            return [value.day, value.month, value.year]
        return [None, None, None]

    def format_output(self, rendered_widgets):
        return u''.join(rendered_widgets)

我做了什么?

子类django.forms.widgets.MultiWidget 实现了一个构造函数,该构造函数在一个 元组。这很重要,因为超类使用此元组的存在来为您处理几件事情。 我的格式输出是直通的,但想法是您可以根据需要在此处添加自定义 html 我还实现了decompress,因为您必须 - 您应该期望在单个value 对象中从数据库中传递值。 decompress 将其分解以显示在小部件中。您在此处如何操作和做什么取决于您,并且取决于小部件。

我没有但可能有的东西被覆盖:

render,这个其实是负责渲染widget,所以子类化这个肯定需要调用superrender方法。您可以通过继承 this 来更改渲染前的显示方式。

例如,djangomarkitup的渲染方法:

def render(self, name, value, attrs=None):
    html = super(MarkItUpWidget, self).render(name, value, attrs)

    if self.auto_preview:
        auto_preview = "$('a[title=\"Preview\"]').trigger('mouseup');"
    else: auto_preview = ''

    html += ('<script type="text/javascript">'
            '(function($)  '
             '$(document).ready(function() '
             '  $("#%(id)s").markItUp(mySettings);'
             '  %(auto_preview)s '
             ');'
             ')(jQuery);'
             '</script>' % 'id': attrs['id'],
                            'auto_preview': auto_preview )
    return mark_safe(html)
value_from_datadict - 见我的问题here。 value_from_datadict 将与此小部件关联的值从使用此表单提交的所有数据的数据字典中提取出来。对于表示单个字段的多小部件,您需要从多个子小部件中重建该值,这就是数据的提交方式。 如果您想使用 django 的媒体表示来检索媒体,_get_media 可能对您有用。默认实现循环请求媒体的小部件;如果您将其子类化并使用任何花哨的小部件,则需要调用超级;如果您的小部件需要任何媒体,那么您需要使用它添加它。

例如,markitup 的 django 小部件是这样做的:

def _media(self):
        return forms.Media(
            css= 'screen': (posixpath.join(self.miu_skin, 'style.css'),
                             posixpath.join(self.miu_set, 'style.css')),
            js=(settings.JQUERY_URL,
                absolute_url('markitup/jquery.markitup.js'),
                posixpath.join(self.miu_set, 'set.js')))
    media = property(_media)

同样,它正在创建一个指向正确位置的路径元组,就像我的小部件在 __init__ 方法中创建了一个小部件元组一样。

我认为这涵盖了MultiWidget 类的重要部分。您正在尝试做什么取决于您创建的内容/您正在使用的小部件,这就是为什么我不能轻易详细介绍的原因。但是,如果您想自己查看基类并查看 cmets,请查看 the source。

【讨论】:

绝对是迄今为止我见过的关于创建多小部件表单字段的最佳主题指南,而且我相信我见过不少! 您能否提供一个示例,说明如何在模型表单中为该表单中的两个字段使用多窗口小部件?还是多小部件旨在拆分字段而不是组合它们? 方法 format_output 已被弃用并且不再存在于 Widget 类中。

以上是关于如何使用 Django 的 MultiWidget?的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 中仅渲染 MultiWidget 的一部分

在 Django 中仅渲染 MultiWidget 的一部分

Django MultiWidget 电话号码字段

Twitter Bootstrap 的 Django 和日期范围选择器组件

不要从 django 表单打印媒体

自定义 django 小部件 - decompress() arg 未填充