Home > Enterprise >  'ModelChoiceField' object is not iterable - calling objects from existing Model
'ModelChoiceField' object is not iterable - calling objects from existing Model

Time:03-06

Losing the will to live here lol - might be fairly obvious that I'm new to Django/Python.

Can't work out what's going wrong here, I'm calling objects from a model that has values in Django Admin but every time I try to fix one thing, it breaks another.

I want to be able to create a new entry from frontend, but I get this error when trying to migrate:

Stack error

  File "/usr/local/lib/python3.6/site-packages/django/forms/fields.py", line 784, in __init__
    self.choices = choices
  File "/usr/local/lib/python3.6/site-packages/django/forms/fields.py", line 801, in _set_choices
    value = list(value)
TypeError: 'ModelChoiceField' object is not iterable

Please see my model below:

models.py

# Model
engineer_shifts = [
    (0,'Shift 1'),
    (1,'Shift 2'),
    (2,'Shift 3')
]

class Engineer(models.Model):
    engineer = models.CharField(max_length=200,default="John Smith",verbose_name="Engineer")
    engineer_shift = models.IntegerField(choices=engineer_shifts,verbose_name="Shift")

    def __str__(self):
        return f"{self.engineer}"

    class Meta:
        verbose_name_plural = 'Engineers'

class CreateHandoff(models.Model):
    handoff_pk = models.AutoField(primary_key=True)
    handoff_date = models.DateField(auto_now_add=True,verbose_name="Handoff Date")
    shift1_lead = models.IntegerField(choices=engineer_picker,verbose_name="Shift 1 Lead")
    shift1_sec = models.IntegerField(choices=engineer_picker,verbose_name="Shift 1 Secondary")

    def __str__(self):
        return f"{self.handoff_date}"
    
    class Meta:
        verbose_name_plural = 'Handoffs'

# Form
engineer_picker = forms.ModelChoiceField(
    queryset=Engineer.objects.all()
    )

class CreateHandoffForm(forms.ModelForm):
    shift1_lead = forms.ChoiceField(
        label = "Select Shift 1 Lead",
        choices = engineer_picker,
        required = True
    )

    shift1_sec = forms.ChoiceField(
        label = "Select Shift 1 Secondary",
        choices = engineer_picker,
        required = True
    )

    class Meta:
        model = CreateHandoff
        fields = ["shift1_lead","shift1_sec"]

CodePudding user response:

You are looking for a ForeignKey, you can make a ForeignKey to refer to a model record, so:

class CreateHandoff(models.Model):
    handoff_pk = models.AutoField(primary_key=True)
    handoff_date = models.DateField(auto_now_add=True,verbose_name="Handoff Date")
    shift1_lead = models.ForeignKey(Engineer, on_delete=models.CASCADE, related_name='lead_handoffs', verbose_name='Shift 1 Lead')
    shift1_sec = models.ForeignKey(Engineer, on_delete=models.CASCADE, related_name='sec_handoffs', verbose_name='Shift 1 Secondary')

    def __str__(self):
        return f"{self.handoff_date}"
    
    class Meta:
        verbose_name_plural = 'Handoffs'

For the ModelForm, you do not need to specify the fields: Django will automatically make ModelChoiceField for these, so:

class CreateHandoffForm(forms.ModelForm):
    class Meta:
        model = CreateHandoff
        fields = ['shift1_lead', 'shift1_sec']
  • Related