I am not getting the proper value of ChoiceField from a fom in views.py

Hi there,

I havea custom User Model. I am trying to get a value of selection from ChoiceField of form in views.py, but instead of returning proper value, it’s returning a string that is '1'.

My models.py is:

class UserManager(BaseUserManager):
    def _create_user(self, email, password, is_staff, is_superuser, is_candidate, is_voter, **extra_fields):
        if not email:
            raise ValueError('Users must have an email address')

        now = timezone.now()
        email = self.normalize_email(email)

        user = self.model(
            username=email,
            email=email,
            is_staff=is_staff, 
            is_active=True,
            is_superuser=is_superuser, 
            is_candidate=is_candidate,
            is_voter=is_voter,
            last_login=now,
            date_joined=now, 
            **extra_fields
        )
        user.set_password(password)
        user.save(using=self._db)
        user.pbc_id = "PBC-" + str(user.pk)
        user.save(using=self._db)
        return user

    def create_user(self, email, password, **extra_fields):
        user = self._create_user(email, password, False, False, False, False, **extra_fields)
        user.save(using=self._db)
        user.pbc_id = "PBC-" + str(user.pk)
        user.save(using=self._db)
        
        return user


    def create_superuser(self, email, password, **extra_fields):
        user=self._create_user(email, password, True, True, False, False, **extra_fields)
        return user


class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=254, null=True, blank=True)
    email = models.EmailField(max_length=254, unique=True)
    first_name = models.CharField(max_length=254, null=True, blank=True)
    last_name = models.CharField(max_length=254, null=True, blank=True)
    pbc_id = models.CharField(max_length=254, null=True, blank=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_candidate = models.BooleanField(default=False)
    is_voter = models.BooleanField(default=False)
    votes = models.IntegerField(default=0)
    last_login = models.DateTimeField(null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    
    USERNAME_FIELD = 'email'
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()

    def get_absolute_url(self):
        return "/users/%i/" % (self.pk)

    def __str__(self) -> str:
        return (self.pbc_id)

My forms.py is:

class CandidateForm(forms.ModelForm):
    candidate = forms.ChoiceField(choices=CANDIDATES, widget=forms.Select)

    class Meta:
        model = User
        fields = ["candidate"]

My views.py is:

def votes(request):
    candidatesfm = CandidateForm(request)

    context = {
            'candidatesfm': candidatesfm
        }
    
    if request.method == 'POST':
        candidatesfm = CandidateForm(request.POST)

        if candidatesfm.is_valid():
                candidate = candidatesfm.data.get("candidate")

                total_votes = 0

                candidates = User.objects.filter(is_candidate=True)

                for cand in candidates:
                    total_votes += int(cand.votes)
                
                if candidate is not None:
                    print(candidate)  # HERE I AM GETTING PRINTED 1 INSTEAD  OF PROPER VALUE, NO MATTER WHAT I SELECT IN CHOICEFIELD
                    messages.info(request, "Candidate " + candidate.pbc_id + " - " + candidate.first_name + " " + candidate.last_name + " has total of " + candidate.votes + " votes and has votes percentage of " + candidate.votes / total_votes + "%.")
                    #print(candidate.votes)
                    return render(request, 'register/votes.html', context)
                else:
                    print("Error")

    return render(request, 'register/votes.html', context)

You don’t show what CANDIDATES is, so we can’t tell what choices is being set to.

Also, you’ve got:
candidate = candidatesfm.data.get("candidate")
which is the unvalidated data submitted by the form.

You should be getting that field from cleaned_data.

Finally, review the docs for ChoiceField. If you’re looking to retrieve an integer value, you may want to use an IntegerField with a SelectWidget.

This is what CANDIDATES is:

cands = User.objects.filter(is_candidate=True)
count = 0
CANDIDATES = []
for ele in cands:
    CANDIDATES += [(count + 1, ele)]

I tried with cleaned_data but results are same.

I don’t want any integer. I want here an instance of User Model which have is_candidate as True as selected from the list of the User Model having similar property (i.e. is_candidate=True) in the ChoiceField of the form.

@KenWhitesell OK I found the solution. I had a mistake in my for loop. I changed from:

to this:

for ele in cands:
    CANDIDATES += [(count, ele)]
    count += 1

Now as I have only two such instances which have is_candidate-True, so I am getting now 0 for first instance and 1 for second instance. But I don’t want this str or int, I want the actual User Model instance here which was selected from the ChoiceField.

How can I accomplish that?

What you’re looking for in this case is the Model Choice Field.

2 Likes