0

I'm new to Django and any help is appreciated, How can I restrict the choice option in one field based on a previous field. For example, if I select 'dog' for animal, I want to remove 'chocolate' from the FOOD_CHOICE. Thank you!!!

ANIMAL_CHOICE = (
     ('a','cat'),
     ('b','dog'),
     ('c','fish'),
)
FOOD_CHOICE = (
      ('a', 'chocolate'),
      ('b', 'kittySnack'),
      ('c', 'steak'),
)

class Animal(models.Model):
    animal = models.CharField(max_length=1, choices= ANIMAL_CHOICE)
    food   = models.CharField(max_length=1, choices= FOOD_CHOICE)
mathque33
  • 81
  • 8

1 Answers1

1

As explained here, you should do the validation on the model form or in the model clean method and raise a ValidationError there.

Here is an example, in which you could override the clean method of your model's form:

forms.py

class AnimalForm(ModelForm):
    class Meta:
        model = Animal
        fields = "__all__"

    def clean(self):
        cleaned_data = super(AnimalForm, self).clean()
        animal = self.cleaned_data.get("animal")
        food = self.cleaned_data.get("food")
        if animal == "b" and food == "a": # Might not work, but this is the general idea
            raise forms.ValidationError("Chocolate can't be selected with Dogs")

N.B.: At the line where I commented that it might not work, you'll have to debug a bit. I don't remember (and I can't test right now) if the cleaned_data returns a tuple or the actual value, or the humand-readable value.

Now, I guess that you want your select in your HTML to dynamically change. For the frontend, you'll need to do a bit of JavaScript. There are many ways on how to do it with JS, but here is one:

(in your template, between <script> tags)

var selectAnimal = document.getElementById("select-animal");
var selectFood = document.getElementById("select-food");

selectAnimal.addEventListener("change", function() {
    if(this.value == "a")
    {
        
        // remove from select the "chocolate" option
        for (var i=0; i<selectFood.length; i++) {
            if (selectFood.options[i].text == 'chocolate')
                selectFood.remove(i);
        }
    }
    else {
        
        // checking if "chocolate" is in select or not
        let has_chocolate = false;
        for (var i=0; i<selectFood.options.length; i++){
            if (selectFood.options[i].text == "chocolate"){
                has_chocolate = true;
            }
        }
        
        if (!has_chocolate){ // if "chocolate" is missing
            option = document.createElement("option");
            option.text = "chocolate";
            option.value = "a";
            selectFood.add(option);
        }
    }
});