Search code examples
pythondjangodjango-modelsdjango-users

Query to extended user model returning error


I am receiving an error when making the following query:

Election.objects.all().exclude(candidate__UserID=request.user).filter(Gender=request.user.Profile.Gender).filter(CandidateReg=True)

To this model:

class Election(models.Model):
    Name = models.CharField(max_length=20)
    CandidateReg = models.BooleanField(default=True)
    VotingOpen = models.BooleanField(default=False)
    Description = models.CharField(max_length=255, null=True, blank=True)
    GENDERS = (("M","Male"), ("F","Female"))
    Gender = models.CharField(max_length=1, choices=GENDERS, default="M")
    Seats = models.IntegerField(default=7)
    FlipGrid = models.URLField(null=True, blank=True)
    Complete = models.BooleanField(default=False)

The problem is described in this error:

Traceback (most recent call last):
      File "/home/elections/venv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
        response = get_response(request)
      File "/home/elections/venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
        response = self.process_exception_by_middleware(e, request)
      File "/home/elections/venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
        response = wrapped_callback(request, *callback_args, **callback_kwargs)
      File "/home/elections/elections-real/elections/views.py", line 139, in add_candidate
        elections = Election.objects.all().exclude(candidate__UserID=request.user).filter(Gender=request.user.Profile.Gender).filter(CandidateReg=True)
      File "/home/elections/venv/lib/python3.6/site-packages/django/utils/functional.py", line 239, in inner
        return func(self._wrapped, *args)
    AttributeError: 'User' object has no attribute 'Profile'

It appears to show the issue is with the reference to Genderdata in the current user's profile - an extension of the user model. This is shown here:

class Profile(models.Model):
    UserID = models.OneToOneField(User, on_delete=models.CASCADE)
    GENDERS = (("M","Male"), ("F","Female"))
    Gender = models.CharField(max_length=1, choices=GENDERS)
    UserTypeID = models.ForeignKey(UserType, on_delete=models.PROTECT, blank=True, null=True)
    EmailConfirmed = models.BooleanField(default=False)

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(UserID=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

How do I correctly reference the Gender attribute of the logged-in user's profile if not the way outlined above?


Solution

  • The reverse accessor of a one-to-one field is always the lower-cased name of the model: so it would be request.user.profile....

    This would be less surprising to you if you followed standard PEP-8 compliant style and named all your fields with lower case - gender, voting_open, email_confirmed etc. Also note it is not best practice to give relationship fields names ending with ID as they give access to the whole related object, not just the ID, so your UserID should be called just user.

    Finally, on gender, please read Falsehoods Programmers believe about Gender and consider whether you really need to ask this information.