Skip to content

Instantly share code, notes, and snippets.

@dokterbob
Created February 15, 2011 20:00
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save dokterbob/828117 to your computer and use it in GitHub Desktop.
Save dokterbob/828117 to your computer and use it in GitHub Desktop.
InlineAdmin mixin limiting the selection of related items according to criteria which can depend on the current parent object being edited.
class LimitedAdminInlineMixin(object):
"""
InlineAdmin mixin limiting the selection of related items according to
criteria which can depend on the current parent object being edited.
A typical use case would be selecting a subset of related items from
other inlines, ie. images, to have some relation to other inlines.
Use as follows::
class MyInline(LimitedAdminInlineMixin, admin.TabularInline):
def get_filters(self, obj):
return (('<field_name>', dict(<filters>)),)
"""
@staticmethod
def limit_inline_choices(formset, field, empty=False, **filters):
"""
This function fetches the queryset with available choices for a given
`field` and filters it based on the criteria specified in filters,
unless `empty=True`. In this case, no choices will be made available.
"""
assert formset.form.base_fields.has_key(field)
qs = formset.form.base_fields[field].queryset
if empty:
logger.debug('Limiting the queryset to none')
formset.form.base_fields[field].queryset = qs.none()
else:
qs = qs.filter(**filters)
logger.debug('Limiting queryset for formset to: %s', qs)
formset.form.base_fields[field].queryset = qs
def get_formset(self, request, obj=None, **kwargs):
"""
Make sure we can only select variations that relate to the current
item.
"""
formset = \
super(LimitedAdminInlineMixin, self).get_formset(request,
obj,
**kwargs)
for (field, filters) in self.get_filters(obj):
if obj:
self.limit_inline_choices(formset, field, **filters)
else:
self.limit_inline_choices(formset, field, empty=True)
return formset
def get_filters(self, obj):
"""
Return filters for the specified fields. Filters should be in the
following format::
(('field_name', {'categories': obj}), ...)
For this to work, we should either override `get_filters` in a
subclass or define a `filters` property with the same syntax as this
one.
"""
return getattr(self, 'filters', ())
@stefanitsky
Copy link

stefanitsky commented Mar 10, 2020

Thanks a lot. BTW, has_key is deprecated (i'm using Django >= 2.2) and if someone is getting error like:

AttributeError: 'collections.OrderedDict' object has no attribute 'has_key'

Just change Line-24:

assert formset.form.base_fields.has_key(field)

For:

assert field in formset.form.base_fields

@dokterbob
Copy link
Author

dokterbob commented Mar 10, 2020 via email

@stefanitsky
Copy link

Great tip! If you are perhaps able to make this a pull request (cllick the edit button on the file in question), I promise that it’ll be immediately accepted! :)

I dont think that is possible, but i created a fork.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment