Skip to content

Instantly share code, notes, and snippets.

@mrob11
Last active October 27, 2020 11:22
Show Gist options
  • Save mrob11/9607834 to your computer and use it in GitHub Desktop.
Save mrob11/9607834 to your computer and use it in GitHub Desktop.
Simple follower/following relationship in Django
$ ./manage.py shell
Python 2.7.5 (default, Aug 25 2013, 00:04:04)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from followers.models import *
>>> john = User.objects.create_user('john', 'lennon@thebeatles.com', 'password')
>>> paul = User.objects.create_user('paul', 'mccartney@thebeatles.com', 'password')
>>> george = User.objects.create_user('george', 'harrison@thebeatles.com', 'password')
>>> ringo = User.objects.create_user('ringo', 'starr@thebeatles.com', 'password')
>>> john.following.add(Follower(following=paul))
>>> john.following.add(Follower(following=george))
>>> paul.following.add(Follower(following=john))
>>> ringo.following.add(Follower(following=john))
>>> ringo.following.add(Follower(following=paul))
>>> ringo.following.add(Follower(following=george))
>>> john.followers.all()
[<Follower: paul follows john>, <Follower: ringo follows john>]
>>> paul.followers.all()
[<Follower: john follows paul>, <Follower: ringo follows paul>]
>>> george.followers.all()
[<Follower: john follows george>, <Follower: ringo follows george>]
>>> john.following.all()
[<Follower: john follows paul>, <Follower: john follows george>]
>>> ringo.following.all()
[<Follower: ringo follows john>, <Follower: ringo follows paul>, <Follower: ringo follows george>]
>>> ringo.followers.all()
[]
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Follower(models.Model):
follower = models.ForeignKey(User, related_name='following')
following = models.ForeignKey(User, related_name='followers')
class Meta:
unique_together = ('follower', 'following')
def __unicode__(self):
return u'%s follows %s' % (self.follower, self.following)
@mrob11
Copy link
Author

mrob11 commented Apr 6, 2020

How can we ensure that follower and following are not same ??
Like John follows John doesn't make any sense?

I would put a check in the Follower.save method to make sure follower and following are not the same user.

Edit: Actually, it's probably better to put that type of validation in a Model Form, or the Model's clean method rather than the Model save method.

@jibachhydv
Copy link

jibachhydv commented Sep 4, 2020

def clean(self):
        if self.follower == self.following:
            raise ValidationError("One Cannot follow themselves")

This can be a one way

@mrob11
Copy link
Author

mrob11 commented Sep 9, 2020

Yeah that looks pretty clean. No pun intended.

@Olamidun
Copy link

Hi Mike, why did you choose to use ForeignKey instead of ManyToMany Relationship?
A user should be able to follow multiple users and multiple users should also be able to follow a user. Is using a foreignkey not going to restrict it to just one user being able to follow multiple users and multiple users not being able to follow a user...or vice versa?

@mrob11
Copy link
Author

mrob11 commented Sep 18, 2020

@Olamidun if I chose a ManyToMany field, that would have to have been implemented directly on the User model which is an unnecessary complication. This method is essentially a through model on a M2M field without declaring it that way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment