Search code examples
djangodjango-adminforeign-keyslimit-choices-to

filtering ForeignKey by object ID


I have a CarType that has a ForeignKey BodyMaterial in my models.py:

class BodyMaterial(models.Model):
    location                = models.ForeignKey('CarType')
    name                    = models.CharField(max_length=255)

class CarType(models.Model):
    name                    = models.CharField(max_length=255)
    default_body_material   = models.ForeignKey(BodyMaterial, null = True, blank = True, default = "", limit_choices_to={'location__exact': 1})

BodyMaterial is an Inline in CarType in my admin.py:

class BodyMaterial_Inline(admin.StackedInline):
    model = BodyMaterial
    extra = 1

class CarType_Admin(admin.ModelAdmin):
    inlines = [BodyMaterial_Inline]

admin.site.register(CarType, CarType_Admin)

I would like to filter the ForeignKey for default_body_material to show only the relevant BodyMaterials (the ones that appear/added on the same admin page). For example, I created a 2 seat CarType and in the same page added some BodyMaterials. Then I create an SVU CarType and some other BodyMaterials. When I go back to the 2 seat CarType, I would like to see only the relevant BodyMaterials in the drop-down for default_body_material.

I try to filter using limit_choices_to on the id. So I'm doing this using post_init because the id for the object in determined in runtime:

def setID(**kwargs):
    instance = kwargs.get('instance')
    default_body_material = instance._meta.get_field_by_name('default_body_material')[0]
    default_body_material.limit_choices_to = {'location__exact': instance.id}

post_init.connect(setID, CarType)

Unfortunately, that does nothing. What am I missing? Is there a beter why of filtering ForeignKey for my purposes (this is probably very basic)?

Note that this question is only for the admin interface.


Solution

  • Just use a custom ModelForm:

    class CarTypeAdminForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super(CarTypeAdminForm, self).__init__(*args, **kwargs)
            # Can't limit it until instance has been saved at least once
            if self.instance.pk:
                self.fields['default_body_material'].queryset = \
                    self.fields['default_body_material'].queryset \
                        .filter(location=self.instance)
    
    class CarTypeAdmin(admin.ModelAdmin):
        form = CarTypeAdminForm
        ...