如何使用 Django 的 MultiWidget?

发布于 2024-09-15 01:41:15 字数 372 浏览 10 评论 0原文

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

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 小部件吗?

The documentation is a bit lacking with respect to this feature.

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]

I can see I need to create a "widgets" property with a list of other widgets, but after that it gets a little Sherlock Holmes.

Would someone please explain to me how to use the MultiWidget widget?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

-黛色若梦 2024-09-22 01:41:15

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

这是我刚刚问的一个问题< /a>:

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,因为您必须这样做 - 您应该期望从单个 value 对象中的数据库。 decompress 将其分解以在小部件中显示。您在这里如何做以及做什么取决于您并且取决于小部件。

我没有但可以重写的东西:

  • render,这实际上负责渲染小部件,因此如果您将其子类化,则肯定需要调用超级渲染方法。您可以通过子类化它来更改渲染之前的显示方式。

例如,django markitup 的渲染方法:

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 - 请参阅我的问题在这里。 value_from_datadict 从该表单提交的所有数据的数据字典中提取与该小部件关联的值。对于代表单个字段的多小部件,您需要从多个子小部件重建该值,这就是提交数据的方式。
  • 如果您想使用 django 的媒体表示形式检索媒体,_get_media 可能对您有用。默认实现会循环请求媒体的小部件;如果你继承它并使用任何奇特的小部件,你需要调用 super;如果您的小部件需要任何媒体,那么您需要使用它来添加它。

例如,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 类的重要部分。您尝试执行的操作确实取决于您创建的内容/您正在使用的小部件,这就是为什么我无法轻松详细说明的原因。但是,如果您想亲自查看基类并查看注释,请查看 来源

Interesting question and I think perhaps deserving of a little more attention in the docs.

Here's an example from 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)

What've I done?

  • subclassed django.forms.widgets.MultiWidget
  • Implemented a constructor that creates several widgets.WidgetName widgets in a
    tuple. This is important because the super class uses the existence of this tuple to take care of several things for you.
  • My format output is pass-through, but the idea is that you can add custom html in here should you wish
  • I've also implemented decompress because you have to - you should expect to be passed values from the database in a single value object. decompress breaks this up for display in the widget. How and what you do here is up to you and depends on the widget.

Things I haven't, but could have, overriden:

  • render, this is actually responsible for rendering widgets, so you definitely need to call the super render method if you subclass this. You can change how things are displayed just before rendering by subclassing this.

Example, django markitup's render method:

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 - See my question here. value_from_datadict pulls the value associated with this widget out of the data dictionary of all submitted data with this form. In the case of a multiwidget representing a single field, you need to reconstruct that value from your multiple sub-widgets, which is how the data will have been submitted.
  • _get_media might be useful for you if you want to retrieve media using django's representation of media. The default implementation cycles the widgets asking for the media; if you subclass it and are using any fancy widgets you need to call the super; if your widget needs any media then you need to add it using this.

For example, markitup's django widget does this:

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)

Again, it is creating a tuple of paths to the correct location, just as my widget has created a tuple of widgets in the __init__ method.

I think that covers it for important parts of the MultiWidget class. What you are trying to do does depend on what you've created/which widgets you're using, which is why I can't go into details easily. However, if you want to see the base class for yourself and take a look at the comments, take a look at the source.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文