Search code examples
pythondjangodjango-users

Trying to use add_notification() method on UserProfile object, ValueError: cannot assign UserProfile - Notification.user must be a User instance


I'm trying to use the default user model in my django application. I created UserProfile objects to have custom/additional fields for users. I'm trying to assign Notification objects to each UserProfile and I have the following code block

allUsers = User.objects.all()
for each in allUsers:
    uprof = UserProfile.objects.get_or_create(user=each)

for u in allUsers:
       if u.userprofile:
           notif1 = u.userprofile.add_notification(title="Welcome to our site " + u.email, body="Your first notification") # error
           notif2 = u.userprofile.add_notification(title="Sample Notification" + u.email, body="Empty template for " + u.email) # also same error

I was running this in a django shell plus. The first for loop iterates through all users and gives them a UserProfile object. The second tries to assign a notification to that user with a userprofile method called add_notification(). This fails and generates the error

ValueError: Cannot assign "<UserProfile: devtest4@gmail.com>": "Notification.user" must be a "User" instance.

I kinda don't really know what this error message means. And even so, I thought this would be the correct way of assigning a UserProfile to every existing User and then adding a notification to each user's respective userprofile. Am I going about this wrong?

user_profile/models.py

class UserProfile(models.Model):
    phone_number    = models.CharField(max_length=15, verbose_name='Phone Number')
    user            = models.OneToOneField(User, on_delete = models.CASCADE)
    api_key         = models.CharField(max_length=200, default='12345678')
    class Meta:
           verbose_name = "User Profile"
           verbose_name_plural = "User Profile"
    def __str__(self):
        return str(self.user.email)

    def add_notification(self, title, body):
        notif = Notification(user=self.user, title=title, body=body)
        notif.save()

notifications/models.py

class Notification(models.Model):

    user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_('receiver'), related_name='notifications_receiver')
    title = models.CharField(_('title'))
    body = models.TextField(_('text'), blank=True)
    timestamp = models.DateTimeField(_('timestamp'), auto_now_add=True)
    is_seen = models.BooleanField(_('seen status'), default=False)
    is_read = models.BooleanField(_('read status'), default=False)

Solution

  • As you can see in your error:

    ValueError: Cannot assign "<UserProfile: devtest4@gmail.com>": "Notification.user" must be a "User" instance. 
    

    you are trying to assign a UserProfile instance to a field that should be a User instance here:

    notif1 = u.userprofile.add_notification(title="Welcome to our site " + u.email, 
                                            body="Your first notification") 
    

    so instead of this:

    for u in allUsers:
           if u.userprofile:
               notif1 = u.userprofile.add_notification(title="Welcome to our site " + u.email, 
                                                       body="Your first notification")
               notif2 = u.userprofile.add_notification(title="Sample Notification" + u.email, 
                                                      body="Empty template for " + u.email) 
    

    do this:

    for u in allUsers:
           if u.userprofile:
               notif1 = u.userprofile.add_notification(user=u, 
                                                       title="Welcome to our site " + u.email, 
                                                       body="Your first notification")
               notif2 = u.userprofile.add_notification(user=u, 
                                                       title="Sample Notification" + u.email, 
                                                       body="Empty template for " + u.email)
    

    and rewrite your method like this:

    def add_notification(self, user, title, body):
        notif = Notification(user=user, title=title, body=body)
        notif.save()