makriss
makriss

Reputation: 53

Django: error while trying to access ManyToMany field

I'm trying to create a twitter like application as a practice project, and following this video tutorial. I've created following models in my app.

class Profile(models.Model):
    user = models.OneToOneField(to=User, on_delete=models.CASCADE)
    bio = models.CharField(max_length=160, blank=True)
    profile_photo = models.ImageField(blank=True, null=True)
    followers = models.ManyToManyField("self", through="Relationship", related_name="follow_to",
                                       symmetrical=False, blank=True)


class Relationship(models.Model):
    user_followed = models.ForeignKey("User", related_name="followed", on_delete=models.CASCADE)
    followed_by = models.ForeignKey("Profile", related_name="follower", on_delete=models.CASCADE)
    timestamp = models.DateTimeField(auto_now=True)

The migrations ran successfully.

After this for testing, I created two users (user1 and user2) with their respective profiles and made user2 to follow user1. Here's the code for that-

Relationship.objects.create(user_followed=user1,followed_by=user2.profile)

This relationship was successfully created. I try the following code to try to get followers of user1-

user1.profile.followers.all()

But above code is giving following errors-

Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/mayank/.pyenv/versions/dwitter/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 535, in __get__
return self.related_manager_cls(instance)
File "/Users/mayank/.pyenv/versions/dwitter/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 821, in __init__
self.target_field_name = rel.field.m2m_reverse_field_name()
File "/Users/mayank/.pyenv/versions/dwitter/lib/python3.8/site-packages/django/db/models/fields/related.py", line 1554, in _get_m2m_reverse_attr
return getattr(self, cache_attr)
AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'

I tried following the method mentioned here, but it is also giving the same error. I'm not sure where have I committed a mistake. I would be thankful if someone can correct me.

Upvotes: 1

Views: 404

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476534

Since you make an ManyToManyField to 'self' both the ForeignKeys should point to Profile:

class Relationship(models.Model):
    followed = models.ForeignKey(
        'Profile',
        related_name='followed',
        on_delete=models.CASCADE
    )
    followed_by = models.ForeignKey(
        'Profile',
        related_name='follower',
        on_delete=models.CASCADE
    )
    timestamp = models.DateTimeField(auto_now=True)

Since now both ForeignKeys point to the same model, there is an ambiguity what the source field, and what the target field is. You resolve this by specifying this with the through_fields=… parameter [Django-doc]:

class Profile(models.Model):
    user = models.OneToOneField(to=User, on_delete=models.CASCADE)
    bio = models.CharField(max_length=160, blank=True)
    profile_photo = models.ImageField(blank=True, null=True)
    followers = models.ManyToManyField(
        'self',
        through='Relationship',
        related_name='follow_to',
        related_fields=('followed', 'followed_by')
        symmetrical=False,
        blank=True
    )

You thus can create a follower Relation with:

Relationship.objects.create(
    followed=user1.profile,
    followed_by=user2.profile
)

Upvotes: 1

Related Questions