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:
http://www.charlesleifer.com/photos/relationship-tables/
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:
# 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:
# 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():
# 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.
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:
/relationships/add/yoko/following/
/relationships/add/the_walrus/blocking/
I hope that people find this project useful! Any suggestions for improvement are greatly appreciated.
how is this better than django-command-extensions graph_model?
http://code.google.com/p/django-command-extensions/wiki/GraphModels
Any thoughts about how this could be integrated into the admin?
If you take a peek at the admin.py, I have it customizing the User admin adding relationships as a tabular inline. This way you can edit a user's relationships in the context of their detail page.
Your app seems to be really cool. It's well written and... contains tests! I'm going to check it soon.
Thanks a lot!
Hm, nice app :)
But why can I view the source, but it‘s not OpenSource released? Please change the LICENSE file ;)
Keba
PS: It would be really cool, if your RSS feed contained the whole blog entry :)
Keba, I admit I don't know much about the ways licenses are to be interpreted. At any rate, I've got a new license on the app:
http://github.com/coleifer/django-relationships/blob/master/LICENSE
stati, not statuses question: how will this work with non-rel? Thanks!
Commenting has been closed, but please feel free to contact me