[Django]-Django admin inlines: get object from formfield_for_foreignkey

19👍

To filter the choices available for a foreign key field in an admin inline, I override the form so that I can update the form field’s queryset attribute. That way you have access to self.instance which is the object being edited in the form. So something like this:

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
        )
        

You don’t need to use formfield_for_foreignkey if you do the above and it should accomplish what you described.

👤dshap

26👍

Another way, that, IMHO, feels cleaner than, but is similar to @erichonkanen’s answer is something like this:

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)

13👍

The answer provided by @mkoistinen is great but django stores parent id in kwargs and not args so it would be correct to extract it like this.

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

7👍

I was able to solve it by using the formfield_for_foreignkey and stripping the object ID from the url. It’s not the sexiest way to get the ID but Django doesn’t provide access to the object ID on the admin object yet (it should).

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)

4👍

This is the solution I came up with, which seems pretty clean

    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)
👤r4F705

0👍

If you are working with an older Django version, it may not yet support the resolver_match attribute.

In that case i found following solution:

    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

Leave a comment