Error: Select a valid choice. That choice is not one of the available choices.

Hi everyone,
I am trying to insert the parent field as a ModelChoiceField in a form, but I keep getting the error: “Select a valid choice. That choice is not one of the available choices.” This happens only for the parent field, while other ModelChoiceField fields like groups and position are working fine.

Also, in the views.py, there’s a piece of code where I set the options for the parent field, so there might be something wrong with it.

But in admin panel, it works fine.

Here is the models.py:

class NewUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_('Emailová adresa'), unique=True, blank=False, null=False)
    username = models.CharField(max_length=150, verbose_name='Přezdívka', unique=True, blank=False, null=False)
    first_name = models.CharField(max_length=150, verbose_name='Křestní jméno', blank=False, null=False)
    last_name = models.CharField(max_length=150, verbose_name='Příjmení', blank=False, null=False)
    permanent_address = models.CharField(max_length=250, verbose_name='Adresa bydliště', blank=False, null=False)
    cin = models.IntegerField(validators=[MaxValueValidator(99999999)], verbose_name='IČ', blank=False, null=False)
    parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, related_name='children', verbose_name='Rodič')
    position = models.ForeignKey(Position, on_delete=models.SET_NULL, max_length=250, verbose_name='Pracovní pozice', blank=True, null=True)
    start_date = models.DateTimeField(default=timezone.now, blank=False, null=False)
    last_login = models.DateTimeField(default=timezone.now, blank=False, null=False)
    date_joined = models.DateTimeField(default=timezone.now, blank=False, null=False)
    is_staff = models.BooleanField(default=False, verbose_name='Člen administrace')
    is_superuser = models.BooleanField(default=False, verbose_name='Superuživatel')
    is_active = models.BooleanField(default=False, verbose_name='Aktivní')
    groups = models.ManyToManyField('auth.Group', related_name='user_groups', blank=True, verbose_name='Skupiny')

    objects = CustomAccountManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username', 'first_name', 'last_name', 'permanent_address', 'cin']

    class Meta:
        verbose_name = 'Uživatel'
        verbose_name_plural = 'Uživatelé'

    def get_groups(self):
        groups = ", ".join([group.name for group in self.groups.all()])
        return f"{groups}"
    get_groups.short_description = "Skupiny"

    def get_subordinates(self):
        subordinate_users = []
        subordinates = list(self.children.all())
        for subordinate_user in subordinates:
            subordinate_users.append(subordinate_user)
            subordinate_users.extend(subordinate_user.get_subordinates())
        return subordinate_users
    
    def get_parents(self):
        parent_users = []
        parent_user = self.user.parent
        while parent_user:
            parent_users.append(parent_user)
            parent_user = parent_user.parent
        return parent_users

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

forms.py:

class CreateNewUserForm(UserCreationForm):
    class Meta:
        model = NewUser
        fields = ['email', 'first_name', 'last_name', 'cin', 'permanent_address', 'groups', 'position', 'parent',]
        widgets = {
            'email': forms.EmailInput(attrs={'class': 'form-control mb-1'}),
            'first_name': forms.TextInput(attrs={'class': 'form-control mb-1'}),
            'last_name': forms.TextInput(attrs={'class': 'form-control mb-1'}),
            'cin': forms.NumberInput(attrs={'class': 'form-control mb-1'}),
            'permanent_address': forms.TextInput(attrs={'class': 'form-control mb-1'}),
        }
        error_messages = {
            'cin': {
                'max_value': 'Maximálně je povoleno 8 čísel.'
            }
        }
    groups = forms.ModelChoiceField(
        queryset=Group.objects.all(),
        widget=forms.Select(attrs={'class': 'form-select mb-1'}),
        required=True,
        label='Oprávnění',
        empty_label=None
    )
    position = forms.ModelChoiceField(
        queryset=Position.objects.all(),
        widget=forms.Select(attrs={'class': 'form-select mb-1'}),
        required=True,
        label='Pracovní pozice',
        empty_label=None
    )
    parent = forms.ModelChoiceField(
        queryset=NewUser.objects.none(),
        widget=forms.Select(attrs={'class': 'form-select mb-1'}),
        required=True,
        label='Nadřízený',
        empty_label=None
    )
            
    password1 = forms.CharField(label="Heslo", widget=forms.PasswordInput(attrs={'class': 'form-control mt-1'}))
    password2 = forms.CharField(label="Heslo pro ověření", widget=forms.PasswordInput(attrs={'class': 'form-control mt-1'}))

And views.py:

@login_required
def user_management(request):
    create_new_user_form = CreateNewUserForm()
    create_new_position_form = CreatePositionForm()
    print(request.POST)
    if request.method == 'POST':
        print("POST request")
        create_new_user_form = CreateNewUserForm(request.POST)
        if create_new_user_form.is_valid():
            print("Formulář je platný")
            create_new_user_form.save()
            messages.success(request, 'Uživatel úspěšně vytvořen.')
            return redirect('index')
        else:
            print(create_new_user_form.errors)
            messages.error(request, 'Nastala chyba.')

    if request.user:
        current_user = request.user
        subordinates_list = current_user.get_subordinates()
        subordinates_list.append(current_user)

        # Seznam hodnot a popisků pro parent (choices)
        choices = ((int(subordinate.pk), str(subordinate)) for subordinate in subordinates_list)

        # Nastavíme choices pro parent field
        create_new_user_form.fields['parent'].choices = choices

    return render(request, 'dashboard/user_management/user_management.html', {
        'current_user': request.user,
        'subordinates': request.user.get_subordinates(),
        'positions': Position.objects.all(),
        'create_new_user_form': create_new_user_form,
        'create_new_position_form': create_new_position_form,
    })

Welcome @marasnetwork !

You’re setting a different attribute of the field than what’s being checked.

The ModelChoiceField uses queryset, not choices.

You need to set the queryset attribute of the field to a queryset. Create a query that returns a queryset of subordinates, and assign that to the queryset attribute of the form field.

Note: You also need to do this on both the GET and POST processing of the form.

(post deleted by author)

Thank you, it is working now! :slight_smile: