Search code examples
pythondjangomany-to-manydjango-ormmanytomanyfield

Why is Django's `add()` method in my `many-to-many` Django models not taking?


Question / Problem:

I am building a Django app, with 2 models: User and Secret. Secrets can be made by Users, and other Users can "like" them. I've setup my likes field as a ManyToManyField, so that Users whom like a Secret can be stored there and later retrieved, etc. However, when I try to query for a User and a Secret and use my_secret.likes.add(my_User) nothing happens. I don't receive an error and when I print my Secret's many-to-many likes field, after the add, I see: secrets.User.None.

Why is my add() method running but I am not receiving any errors, and why is my User not properly being added to my Secret's likes?

Note: I've saved both the User and Secret objects upon initial creation. Outside this application I've been able to use the add() method just fine, but in those scenarios I was creating objects in the moment, and not retreiving already existing objects.

Is there a different way to handle add() when using data retreived from a Query? That's my only other line of reasoning right now, and I've followed the documentation here exactly: Django Many-to-Many Docs

I also apologize if this was answered elsewhere on the site. I did find one other post here, but there was no solution provided, granted they were experiencing the exact same issue.

My Models:

class User(models.Model):
    """
    Creates instances of a `User`.

    Parameters:
    -`models.Model` - Django's `models.Model` method allows us to create new models.
    """

    first_name = models.CharField(max_length=50) # CharField is field type for characters
    last_name = models.CharField(max_length=50)
    email = models.CharField(max_length=50)
    password = models.CharField(max_length=22)
    created_at = models.DateTimeField(auto_now_add=True) # DateTimeField is field type for date and time
    updated_at = models.DateTimeField(auto_now=True) # note the `auto_now=True` parameter
    objects = UserManager() # Attaches `UserManager` methods to our `User.objects` object.

class Secret(models.Model):
    """
    Creates instances of a `Secret`.

    Parameters:
    -`models.Model` - Django's `models.Model` method allows us to create new models.
    """

    description = models.CharField(max_length=100) # CharField is field type for characters
    user = models.ForeignKey(User, related_name="secrets") # One-to-Many Relationship
    likes = models.ManyToManyField(User) # Many to Many Relationship
    created_at = models.DateTimeField(auto_now_add=True) # DateTimeField is field type for date and time
    updated_at = models.DateTimeField(auto_now=True) # note the `auto_now=True` parameter
    objects = SecretManager() # Attaches `SecretManager` methods to our `Secret.objects` object.

Problem Example:

The model migrates fine, everything seems to be in proper syntax. However, when I try and retrieve a User and a Secret, and add the User to the Secret.likes, the add() method gives no errors, runs, but no objects are saved.

Here's an example:

tim = User.objects.get(email="tim@tim.com") # Gets a user object
my_secret = Secret.objects.get(id=2) # Gets a secret object
# This is where nothing seems to happen / take:
my_secret.likes.add(tim) # add() method per Django many-to-many docs
print my_secret.likes # returns: `secrets.User.None` -- why?

Why when printing my_secret.likes above, is nothing printed?

Especially when: tim.secret_set.all() shows the secret containing an id=2 as in the above example....so the User is recording the relationship with the Secret, but the Secret is not recording any relationship with the User. What am I doing wrong?


Solution

  • You need to call the all method of the many-to-many field to view all related objects:

    print my_secret.likes.all()
    #                     ^^^^^