Search code examples
pythondjangodjango-modelsdjango-viewsdjango-users

User Follower model on Django. Cannot use add() on a ManyToManyField which specifies an intermediary model. Use accounts.Contact's Manager instead


I am new to Django, Please forgive any silly mistakes in code or logic,

Intro: I am trying to create a user follower model in Django. Where users can follow and unfollow other users on the sites

Error: I have made the models for my follow/unfollow I have also made the views I am getting this error

AttributeError at /accounts/admin/follow/
Cannot use add() on a ManyToManyField which specifies an intermediary model. Use accounts.Contact's Manager instead. 

The obj.followers.add(user) is highlighted in the traceback as the origin of the error

Below are my models.py

from django.contrib.auth.models import User
class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    city = models.CharField(max_length=100)
    country = models.CharField(max_length=100)
    def get_absolute_url(self):
        return reverse('accounts:profile', kwargs={'username': self.user.username})

class Contact(models.Model):
    user_from = models.ForeignKey(User, related_name='suppporter')
    user_to = models.ForeignKey(User, related_name='leader')

    def __str__(self):
        return '{} follows {}'.format(self.user_from, self.user_to)


User.add_to_class('following',
                  models.ManyToManyField('self', through=Contact, related_name='followers', symmetrical=False))

I think the models.py may be good. The fault I believe is in my views. Below is my view.py

class FollowToggle(LoginRequiredMixin, RedirectView):

    def get_redirect_url(self, *args, **kwargs):
        username = self.kwargs.get('username')
        print(username + " This is the user who will be followed") # This prints correct
        profile = get_object_or_404(Profile, user__username=username)
        print(profile) # This prints correct
        obj = get_object_or_404(User, username=username)
        print(obj) # This prints correct
        url_ = profile.get_absolute_url()
        print(url_) # This prints correct
        user = self.request.user
        print(user) # This prints correct
        if user.is_authenticated():
            if user in obj.followers.all(): # I know this is the source of the error.
                obj.followers.remove(user)
            else:
                obj.followers.add(user)
        return url_

Below are the Urls.py just in case

url(r'^(?P<username>[-\w]+)/follow/$', views.FollowToggle.as_view(), name='follow'),

Solution

  • You cannot use add and remove method for manytomany relation defined through third model. From the docs:

    Unlike normal many-to-many fields, you can’t use add(), create(), or set() to create relationships

    Instead you should use Contact manager:

    if user.is_authenticated():
        if user in obj.followers.all(): # I know this is the source of the error.
            Contact.objects.filter(user_to=obj, user_from=user).delete()
        else:
            Contact.objects.create(user_to=obj, user_from=user)