Limiting choices in django dynamically (call-back function?)

42 Views Asked by At

I am relatively new to Django and this is my first question on Stackoverflow. So pleas bear with me if not ideally formulated.

My Problem: I have a Model Animal with two fields that are ForeignKey based (species,breed) . Only those breeds should be shown that are available as per the entered/given species. This reduction of choice options shall take place when a) a new Animal record is created, b) the specie value is changed and the breed options are looked up newly and c) when the breed for a given animal shall be changed. This shall happen both in the Admin UI as well as in the apps UI via Django Forms

Originally I thought the the limit_choices_to attribute in conjunction with a Q could do the trick but it did not, neither I was able to got it working callable defined.

By reading various posts I have found a way to interfere for method c) which does not work for a) and b)

Here are my data:


Models.py

class Specie(models.Model):
    specie      = models.CharField(primary_key=True, max_length=1, )
    specieText  = models.CharField(                  max_length=24,)

    class Meta:
        ordering = ['specieText']

    def __str__(self):
        return self.specieText

class Breed(models.Model):
    specie      = models.ForeignKey('Specie',     on_delete=models.CASCADE,)
    breed       = models.CharField(max_length=2,)
    breedText   = models.CharField(max_length=24, blank=True,)

    class Meta:
        ordering = ['breedText']

    def __str__(self):
        return self.breedText



class Animal(models.Model):
    specie      = models.ForeignKey('Specie',       on_delete=models.CASCADE,)
    breed       = models.ForeignKey('Breed',        on_delete=models.CASCADE,)
    name        = models.CharField(max_length=24,)
    name        = models.CharField(max_length=24,)
    birthdate   = models.DateField()

    class Meta:
        ordering = ['name']

        def __str__(self):
            return self.name

forms.py

class AnimalForm(forms.ModelForm):

    class Meta:
        model = Animal
        fields = "__all__" 
    
    def __init__(self, *args, **kwargs):
        super(AnimalForm, self).__init__(*args, **kwargs)
        if self.instance.id:
            if self.instance.specie_id:
                breeds = Breed.objects.filter(specie=self.instance.specie)

                breed_field = self.fields['breed'].widget
                breed_choices = []
                breed_choices.append(('', '---------'))
                for breed in breeds:
                    breed_choices.append((breed.id, breed.breedText))
                breed_field.choices = breed_choices

admin.py

class AnimalAdmin(admin.ModelAdmin):

    form = AnimalForm

admin.site.register(Specie)
admin.site.register(Breed)
admin.site.register(Animal, AnimalAdmin)

https://stackoverflow.com/questions/41466993/django-limiting-choices-in-a-form-after-a-selection suggest that one hs to use an AJAX-based Django addon (Smart Select) but there might be a better way in the meantime?

Any help to get the above problem reflected in django code or hints how it could be resolved would be sooo much appreciated

I tried the approach via

  • for field breed I tried field attribute limit_choices_to with Q(species=species) Effect: Empty list of breed options on create and update

  • tried in admin.py for AnimalAdmin the formfield_for_foreignkey approach (but there is no access to the data as such, soany access to the specie field fails) Effect: Runtime error

def formfield_for_foreignkey(self, db_field, request, **kwargs):
      if db_field.name == 'breed':
        specie = request.animal.specie
        kwargs['queryset'] = Breed.objects.filter(specie=specie)
      return super().formfield_for_foreignkey(db_field, request, **kwargs)

and to my understanding this would have anyway only worked in the admin UI

  • init approach as above in forms.py Effect: in app UI on create full list of breeds even so a species is entered(e.g. dog) same on update, in admin UI on create full list of breeds even so specie is entered, on update the reduced breed list appears as drop down but when species of animal is changed (e.g. wrongly entered originally) the breed list for new species is wrong left as dog breeds when changed to cat
0

There are 0 best solutions below