【问题标题】:django admin inlines: get object from formfield_for_foreignkeydjango admin inlines:从 formfield_for_foreignkey 获取对象
【发布时间】:2014-02-15 17:03:52
【问题描述】:

我正在尝试在 django 管理员内联中过滤外键字段中显示的选项。因此,我想访问正在编辑的父对象。我一直在研究,但找不到任何解决方案。

class ProjectGroupMembershipInline(admin.StackedInline):
    model = ProjectGroupMembership
    extra = 1
    formset = ProjectGroupMembershipInlineFormSet
    form = ProjectGroupMembershipInlineForm

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        if db_field.name == 'group':
            kwargs['queryset'] = Group.objects.filter(some_filtering_here=object_being_edited)
        return super(ProjectGroupMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)

我已经验证了编辑对象时 kwargs 是空的,所以我无法从那里获取对象。

有什么帮助吗?谢谢

【问题讨论】:

标签: python django django-admin


【解决方案1】:

这是我想出的解决方案,看起来很干净

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "group":
            parent_id = request.resolver_match.kwargs['object_id']
            kwargs["queryset"] = Group.objects.filter(some_column=parent_id)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

【讨论】:

    【解决方案2】:

    @mkoistinen 提供的答案很棒,但是 django 将父 ID 存储在 kwargs 而不是 args 中,因此这样提取它是正确的。

    parent_id = request.resolver_match.kwargs.get('object_id')
    

    【讨论】:

      【解决方案3】:

      另一种方式,恕我直言,感觉比@erichokanen 的答案更干净,但类似于@erichokanen 的答案是这样的:

      class ProjectGroupMembershipInline(admin.StackedInline):
          # irrelevant bits....
      
          def formfield_for_foreignkey(self, db_field, request, **kwargs):
              if db_field.name == "group":
                  try:
                      parent_id = request.resolver_match.args[0]
                      kwargs["queryset"] = Group.objects.filter(some_column=parent_id)
                  except IndexError:
                      pass
              return super().formfield_for_foreignkey(db_field, request, **kwargs)
      

      【讨论】:

        【解决方案4】:

        我能够通过使用 formfield_for_foreignkey 并从 url 中剥离对象 ID 来解决它。这不是获取 ID 的最性感方式,但 Django 尚未提供对 admin 对象上的对象 ID 的访问(它应该)。

        class ObjectAdmin(admin.ModelAdmin):
        
            def formfield_for_foreignkey(self, db_field, request, **kwargs):
                obj_id = request.META['PATH_INFO'].rstrip('/').split('/')[-1]
                if db_field.name == 'my_field' and obj_id.isdigit():
                    obj = self.get_object(request, obj_id)
                    if obj:
                        kwargs['queryset'] = models.Object.objects.filter(field=obj)
                return super().formfield_for_foreignkey(db_field, request, **kwargs)
        

        【讨论】:

        • 这个解决方案是正确的,因为它在没有自定义表单的情况下适用于所有场景。对于最新版本的 Django(截至 3.0),您应该使用 [-2] 而不是 [-1]
        【解决方案5】:

        为了过滤可用于管理内联中的外键字段的选项,我覆盖了表单,以便可以更新表单字段的 queryset 属性。这样您就可以访问self.instance,这是表单中正在编辑的对象。所以是这样的:

        class ProjectGroupMembershipInlineForm(forms.ModelForm):
            def __init__(self, *args, **kwargs):
                super(ProjectGroupMembershipInlineForm, self).__init__(*args, **kwargs)
                self.fields['group'].queryset = Group.objects.filter(some_filtering_here=self.instance)
        

        如果您执行上述操作,则无需使用formfield_for_foreignkey,它应该可以完成您描述的操作。

        【讨论】:

        • 您应该进一步指出,父对象应该可以作为 self.instance 上的一个字段,它不是父对象,而是 内联对象。但是,这不适用于新的内联对象,因为关系还不存在。
        猜你喜欢
        • 1970-01-01
        • 2012-09-23
        • 2011-09-16
        • 2014-12-25
        • 2013-09-13
        • 1970-01-01
        • 2011-06-04
        • 2015-04-06
        • 2013-04-12
        相关资源
        最近更新 更多