Home > other >  InlineModelAdmin.get_queryset() how to access parent object?
InlineModelAdmin.get_queryset() how to access parent object?

Time:09-28

In the Django admin, I have an Inline, and I would like to filter the list of rows by the parent object.

I can override get_queryset(request) in my Inline, but I don't have access to the parent object.

This snippet is from Django's options.py:

    def get_formset_kwargs(self, request, obj, inline, prefix):
        formset_params = {
            "instance": obj,
            "prefix": prefix,
            "queryset": inline.get_queryset(request),
        }

This would by immediately solved, if Django would provide obj as an argument to inline.get_queryset().

How to implement a get_queryset() of an InlineModelAdmin instance, so that it has access to obj?

class ChildInline(admin.TabularInline):
    ...

    def get_queryset(self, request):
        ???? how to get the parent object?

CodePudding user response:

These lines of code are the implementation of how inline admin instance are instantiate in Django

def get_inline_instances(self, request, obj=None):
    inline_instances = []
    for inline_class in self.get_inlines(request, obj):
        inline = inline_class(self.model, self.admin_site)
        if request:
            if not (
                inline.has_view_or_change_permission(request, obj)
                or inline.has_add_permission(request, obj)
                or inline.has_delete_permission(request, obj)
            ):
                continue
            if not inline.has_add_permission(request, obj):
                inline.max_num = 0
        inline_instances.append(inline)
    
    return inline_instances

as you can see there is no obj passed to the inline_class so normally you can't access the parent instance.

Override this function in your parent model's admin class and use assigned attribute 'parent_obj' in your get_queryset method will make it work.

# parent admin class

def get_inline_instances(self, request, obj=None):
    inline_instances = super().get_inline_instances(request, obj)
    for inline_instance in inline_instances:
        inline_instance.parent_obj = obj
    return inline_instances

# inline admin class

def get_queryset(self, request):
    self.parent_obj  # you can now access your parent obj
    

CodePudding user response:

I found this dirty hack. In my case Event is the parent-model:

class ChildInline(admin.TabularInline):
    ...

    def get_queryset(self, request):
        # dirty hack to get the parent-object (event).
        # Please fix it and tell me,
        # if you know a better way to get it.
        event_id = request.path_info.split('/')[-2]
        event = Event.objects.get(id=event_id)
        ...
  • Related