Limiting choices for ForeignKeyField in django admin

Let’s get straight to the problem. If you have your models like this:

class Photo(models.Model):
  item = models.ForeignKey(Item, related_name='photos')

class Item(models.Model):
  primary_photo = models.ForeignKey(Photo, null=True)

And you want to limit ‘primary_photo’ to be selectable only from the ‘photos’ set in Django admin. What do you do?

Django admin uses ChoiceField for ForeignKeys so we need to limit the choices somehow. The problem is, it has to be dynamic at runtime. Limitation could be done in the model by setting ‘choices’ for the ForeignKey, but that would only allow using static values.

Another way would be to use this method:

class ItemAdmin(admin.ModelAdmin):
  def formfield_for_dbfield(self, db_field, **kwargs)

Here you can override what type of formfield is created and whatnot. The problem still is that there is no way to get hold of the actual object. And we need that to get the queryset of photos.

The real kicker is ‘get_form’. Here we have access to request and our object. We have everything we need:

class ItemAdmin(admin.ModelAdmin):
  def get_form(self, request, obj=None, **kwargs):
    form = super(ItemAdmin, self).get_form(request, obj, **kwargs)
    form.base_fields['item'].queryset = obj.photos.all()
    return form

Also, the same works in any other ChoiceField if you ever need that.

Written 2010-10-28 06:50 and tagged with howto, django.

Ilkka Hakkari

entrepreneur, co-founder and guru at haltu