Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering django admin inline - limit the choices list

Given my inline admin:

class TestInlineAdmin(admin.TabularInline):
    model = Test.questions.through
    extra = 0  

and then

class QuestionAdmin(admin.ModelAdmin):
    inlines = [TestInlineAdmin, ]

Test model has question field which is ManyToMany. And i am normally able to edit the question list directly from Test model. But i want to be able to choose the Tests from inline admin within QuestionAdmin (so, in reverse). This works. But i need to filter the Test objects in this inline, so the list of choices would show me only Test.objects.filter(applicable=False).

inline admin item

I've tried to use get_queryset, but this seems to have no effect on the choice list, it's only filtering the the actual referenced items in inline, but the list of choices for the new item always shows me the complete unfiltered queryset for Test model.

Overriding formfield_for_manytomany does not work in inline - it's not executed at all. Would it be possible somehow with formfield_overrides? Or, as i believe the only way would be to customize the inline form?

-Edit-

My model where the ManyToMany is defined:

class Test(models.Model):
    title = models.CharField(max_length=80)
    description = models.TextField(null=True)
    position = models.ForeignKey('repository.Position', on_delete=models.CASCADE, null=True)
    questions = models.ManyToManyField('questions.Question')
    applicable = models.BooleanField(default=False)

-- Edited -- traceback after proposal by Willem

2021-09-03 07:50:37 | ERROR | /usr/local/lib64/python3.6/site-packages/django/utils/log.py | log_response | - Internal Server Error: /admin/questions/question/45/change/
Traceback (most recent call last):
  File "/usr/local/lib64/python3.6/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/usr/local/lib64/python3.6/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 614, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/sites.py", line 233, in inner
    return view(request, *args, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 1656, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
  File "/usr/local/lib64/python3.6/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 1534, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 1598, in _changeform_view
    formsets, inline_instances = self._create_formsets(request, obj, change=True)
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 1954, in _create_formsets
    for FormSet, inline in self.get_formsets_with_inlines(*get_formsets_args):
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 798, in get_formsets_with_inlines
    yield inline.get_formset(request, obj), inline
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 2053, in get_formset
    fields = flatten_fieldsets(self.get_fieldsets(request, obj))
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 335, in get_fieldsets
    return [(None, {'fields': self.get_fields(request, obj)})]
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 326, in get_fields
    form = self._get_form_for_get_fields(request, obj)
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 2138, in _get_form_for_get_fields
    return self.get_formset(request, obj, fields=None).form
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 2135, in get_formset
    return inlineformset_factory(self.parent_model, self.model, **defaults)
  File "/usr/local/lib64/python3.6/site-packages/django/forms/models.py", line 1082, in inlineformset_factory
    FormSet = modelformset_factory(model, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/forms/models.py", line 879, in modelformset_factory
    error_messages=error_messages, field_classes=field_classes)
  File "/usr/local/lib64/python3.6/site-packages/django/forms/models.py", line 555, in modelform_factory
    return type(form)(class_name, (form,), form_class_attrs)
  File "/usr/local/lib64/python3.6/site-packages/django/forms/models.py", line 258, in __new__
    apply_limit_choices_to=False,
  File "/usr/local/lib64/python3.6/site-packages/django/forms/models.py", line 179, in fields_for_model
    formfield = formfield_callback(f, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/django/contrib/admin/options.py", line 172, in formfield_for_dbfield
    formfield.widget, db_field.remote_field, self.admin_site, **wrapper_kwargs
AttributeError: 'dict' object has no attribute 'widget'
like image 451
Tomasz Szkudlarek Avatar asked Sep 06 '25 07:09

Tomasz Szkudlarek


1 Answers

You can limit the QuerySet of the TestInlineAdmin with:

class TestInlineAdmin(admin.TabularInline):
    model = Test.questions.through
    extra = 0
    
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'test':
            kwargs['queryset'] = Test.objects.filter(applicable=False)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)
like image 129
Willem Van Onsem Avatar answered Sep 07 '25 21:09

Willem Van Onsem