我正在尝试在 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为空,所以我无法从那里获取对象。
请问有什么帮助吗?谢谢
另一种方式,恕我直言,感觉比 @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)
为了过滤管理内联中外键字段的可用选项,我覆盖了表单,以便可以更新表单字段的
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
,它应该可以完成您所描述的任务。
@mkoistinen 提供的答案很棒,但是 django 将父 ID 存储在 kwargs 而不是 args 中,因此像这样提取它是正确的。
parent_id = request.resolver_match.kwargs.get('object_id')
我能够通过使用 formfield_for_foreignkey 并从 url 中删除对象 ID 来解决这个问题。这不是获取 ID 的最性感的方式,但 Django 还没有提供对管理对象上的对象 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)
这是我想出的解决方案,看起来很干净
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)
如果您使用的是较旧的 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