I recently posted on writing an app that allows you to describe relationships between Django’s built-in auth.users. As far as I know the state-of-the-art for this is django-friends and django-simple-friends. django-friends does some things that are missing in my implementation, specifically the support for invitations, but I believe my app improves on the modelling and flexibility of the types of relationships that can be established between users.
Relationships between objects with metadata are ideal for a many-to-many through. Here’s how the schema looks — I’ve put a dotted line around the User model since it shouldn’t be modified directly:
Modelling this in Django is straightforward, but getting the relationships onto the User’s default manager and creating a querying interface that makes sense required a little bit of work. With just the models, it is possible to query Relationship.objects and to query Users using the related names, but this isn’t very pretty:
syntax:python # get who a user follows User.objects.filter( to_users__from_user=user, to_users__status=status_following)
I ended up wrapping this functionality into a dynamically created ManyRelatedManager, allowing you to do something like this:
syntax:python # get who a user follows user.relationships.following()
The ManyRelatedManager knows about the through model and adds the correct core_filter and column mapping so you also get all the default manager methods, like all(), filter() and clear():
syntax:python # is john following anybody named yoko? john.relationships.filter(username='Yoko') # returns a queryset of User objects
Additionally, because relationship statuses are normalized into a separate model, statuses can be defined as “private” or “login_required” which is useful for things like who a user may be blocking. As many different types of relationship statuses as you need can be created through the database and the views will know how to handle them.
Now with views
Due to the way the data is modelled, three ‘types’ of relationships can be described. One-way from a user, one-way to a user, and symmetrical. These map to Twitter’s “following” and “followers” and Facebook’s “friends”. RelationshipStatus objects ask for slugs for these statuses so views can be dynamically created for each relationship type. This allows for urls like the following:
/relationships/john/following/ /relationships/john/followers/ /relationships/john/friends/
Creating relationships is equally simple:
I hope that people find this project useful! Any suggestions for improvement are greatly appreciated.