django admin inlines:从formfield_for_foreignkey获取对象

uubf1zoe  于 2023-10-21  发布在  Go
关注(0)|答案(6)|浏览(147)

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

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是空的,所以我不能从那里获取对象。
有什么需要帮忙的吗?谢谢

elcex8rz

elcex8rz1#

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

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)
ia2d9nvy

ia2d9nvy2#

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

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

如果你做了上面的事情,你不需要使用formfield_for_foreignkey,它应该完成你所描述的事情。

a11xaf1n

a11xaf1n3#

@mkoistinen提供的答案很棒,但是django将parent id存储在kwargs中,而不是args中,所以像这样提取它是正确的。

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

mwkjh3gx4#

我能够通过使用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)
nle07wnf

nle07wnf5#

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

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)
3ks5zfa0

3ks5zfa06#

如果你使用的是较旧的Django版本,它可能还不支持resolver_match属性。
在这种情况下,我找到了以下解决方案:

def formfield_for_foreignkey(self, db_field, request, *args, **kwargs):
        field = super(ProjectGroupMembershipInline, self).formfield_for_foreignkey(db_field, request, *args, **kwargs)
        if db_field.name == 'group':
            resolved_url = resolve(request.path.replace('/{}/'.format(get_language()), '/'))  # remove localisation of url
            if resolved_url and resolved_url.args:  # check we are not in changelist view
                field.queryset = field.queryset.filter(pk=resolved_url.args[0]))  # obj id first and only arg for view.
        return field

相关问题