为Foreignkey字段向窗口小部件输出添加额外数据

时间:2014-09-04 04:28:33

标签: django django-forms django-widget

说我有以下型号......

class Person(models.Model):
   name = models.CharField()
   specialty = models.CharField()

class Team(models.Model):
    captain = models.ForeignKey(Person)
    vice_captain = models.ForeignKey(Person)

我有一个创建团队的表格......

class TeamForm(ModelForm):
     class Meta:
          model = Team
          widgets['vice_captain'] = MySelectWidget()

我还对表格有一个额外的限制,即副队长必须具有与队长相同的专长。我已经在表单干净等中实现了检查,但希望UI能够“过滤”自己。我已经决定不使用ajax来填充/过滤字段,而是将html'data-'标签添加到窗口小部件输出中,然后使用javascript隐藏选项。

我编写了一个与Select小部件一起使用的小部件(和javascript)。这是(注意这是从我的实际代码中简化,但应该工作)。

class Select_with_Data(forms.Select):
    # Not sure if this is necessary.
    allow_multiple_selected = False

    def render_option(self, selected_choices, option_value, option_label):

        # This paragraph is copied from django Select.
        option_value = force_text(option_value)
        if option_value in selected_choices:
            selected_html = mark_safe(' selected="selected"')
            if not self.allow_multiple_selected:
                # Only allow for a single selection.
                selected_choices.remove(option_value)
        else:
            selected_html = ''

        # My custom code to add data-specialty attributes to <option> tags.
        # Get the object to filter upon.
        obj = self.choices.queryset.get(pk=option_value)
        # Get the data field.
        data_field = getattr(obj, 'specialty', False)
        # If the data field has a value set, add it to the return html.
        # Need to check if the data_field has a pk (ie is a ForeignKey field), and handle it appropriately.
        if data_field:
            selected_html += ' data-{0}={1}'.format( 'specialty', str(getattr(data_field, 'pk', data_field)) )

        # This paragraph is copied from django Select.
        return format_html('<option value="{0}" {1}>{2}</option>',
                           option_value,
                           selected_html,
                           force_text(option_label))

但现在我已经决定要收音机按钮,而不是选择列表。我的问题是,尝试在无线电小部件的渲染器中使用与上面类似的代码失败,因为没有设置self.choices.queryset,所以我无法访问我需要的信息。 如何获取所需信息,这是我想要的最佳方式吗?

我甚至修改了核心django文件,以查看查询集消失的位置。 RadioSelect子类RendererMixin。 self.choices.queryset在 init ,render和get_renderer?子函数中可用? (这个词的功能是什么?)。 RadioSelect的渲染器是RadioFieldRenderer,它是ChoiceFieldRenderer的子类。在其 init 中进行渲染,但查询集已经消失(它设置了自己的self.choices,但即使在 init 中的那一步之前,也没有设置self.choices)。

1 个答案:

答案 0 :(得分:4)

我发现了一些不同的方法来实现我想要的目标。

1:编写一个子类Forms.Widget的自定义小部件。这样可以完全控制,不会尝试“使用”核心类。我使用此链接获取灵感,https://djangosnippets.org/snippets/2589/

2:修改选项元组(value,label),并将其更改为(value,label,object)(例如)。以下链接提供了执行此操作的代码:http://srcmvn.com/blog/2013/01/15/django-advanced-model-choice-field/