14

I am playing with relationships in Django/python and I am wondering how you guys would create a relationship between a User and his followers and a Follower to the users he follows.

Would love to read your opinion...

Dan Hanly
  • 7,829
  • 13
  • 73
  • 134
Tony
  • 2,382
  • 7
  • 32
  • 51
  • 1
    Unless you've got a specific programming-related question, this is better suited as a post in a forum. – patrickn May 15 '12 at 13:55
  • 1
    @patrickn most probably yes but it could also be seen as a question. Since I don't have a clue were to start I ask about it. – Tony May 15 '12 at 14:00

3 Answers3

26

First, you should understand how to store additional information about users. It requires another model that has a relation to one user, the "profile" model.

Then, you could use an M2M field, assuming you'd use django-annoying, you could define your user profile model as such:

from django.db import models

from annoying.fields import AutoOneToOneField

class UserProfile(models.Model):
    user = AutoOneToOneField('auth.user')
    follows = models.ManyToManyField('UserProfile', related_name='followed_by')

    def __unicode__(self):
        return self.user.username

And use it as such:

In [1]: tim, c = User.objects.get_or_create(username='tim')

In [2]: chris, c = User.objects.get_or_create(username='chris')

In [3]: tim.userprofile.follows.add(chris.userprofile) # chris follows tim

In [4]: tim.userprofile.follows.all() # list of userprofiles of users that tim follows
Out[4]: [<UserProfile: chris>]

In [5]: chris.userprofile.followed_by.all() # list of userprofiles of users that follow chris
Out[5]: [<UserProfile: tim>]

Also, note that you could check / reuse apps like django-subscription, django-actstream, django-social (harder to use probably)...

You might want to take a look at the django packages for notifications and activities as they all require some follow/subscription database design.

JayTurnr
  • 157
  • 1
  • 11
jpic
  • 32,891
  • 5
  • 112
  • 113
  • 1
    I have Created a UserProfile. I think a manytomanyfield is the way i should go. But in this line chris.userprofile.followed_by.all() <-- did you define a followed_by function? – Tony May 15 '12 at 14:57
  • 1
    Actually, followed_by is the **related_name** of the UserProfile.follows field. By default, it would be userprofile_set which is not really informative. – jpic May 15 '12 at 15:01
  • And what about feeds? Like fb's news feed? – cold_coder Jul 12 '15 at 16:49
  • 1
    For this to work for me, I also had to set symmetrical=False as detailed in this post: https://stackoverflow.com/a/42040848/1991735 – Michael Murphy Mar 05 '19 at 00:36
4

This is how I would do it:

class Tweeter(models.Model):  
    user = models.ManyToManyField('self', symmetrical=False, through='Relationship')

class Relationship(models.Model):  
    who = models.ForeignKey(Tweeter, related_name="who")
    whom = models.ForeignKey(Tweeter, related_name="whom")

In the shell,

In [1]: t = Tweeter()

In [2]: t.save()

In [3]: f = Tweeter()

In [4]: f.save()

In [5]: r=Relationship()

In [6]: r.who=t

In [7]: r.whom=f

In [8]: r.save()

In [18]: Relationship.objects.all()[0].who.id
Out[18]: 1L

In [19]: Relationship.objects.all()[0].whom.id
Out[19]: 2L

zubinmehta
  • 4,368
  • 7
  • 33
  • 51
1

Edit: Makes more sense to use ManyToManyField, as the commenter suggests. Users can have 0-x User followers, and Users can follow 0-x Users.

https://docs.djangoproject.com/en/1.3/ref/models/fields/#manytomanyfield

Without going into code, not much more to be said.

patrickn
  • 2,501
  • 4
  • 22
  • 21
  • 1
    An FK is useful for a 0:1 relation. In the case you're attempting to describe, a user can have 0:n followers and he can follow 0:n users. Thus, the relation would be n:m. – jpic May 15 '12 at 14:27
  • I stand corrected, forgot about the 0 followed users/0 followers case. – patrickn May 15 '12 at 14:29
  • 1
    Rather, the 'many followed' and 'many followers', as an FK only allows to relate to one user. – jpic May 15 '12 at 14:29
  • 1
    Also you cannot add an M2M between user and user unless using the unsupported [contribute to class method](http://stackoverflow.com/questions/2357528/explanation-of-contribute-to-class). – jpic May 15 '12 at 14:54