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