views:

44

answers:

2

I'm serializing User objects to JSON, and I'd like to indicate in the JSON response whether the serialized user is friends with the user making the request.

I've added a to_dict() method to my User model that does the pre-processing necessary to serialize the object--that would be a nice place to add an attribute indicating friendship, but since User.to_dict() doesn't have access to the request object, I can't seem to do it there.

Doing it in a view is easy, but I don't want to repeat that code in other views. I'd like to "upgrade" User objects to request-aware User objects.

The django.contrib.auth User model has an is_authenticated attribute, which is really an attribute of the request and not of the model--that attribute only makes sense within the context of a particular web request.

It's as if I should replace request.user with an instance of RequestUser, a new class that takes a User and a Request and adds request-specific attributes. What's a clean way to do that?

+1  A: 

This doesn't really answer your question, but are you sure you want to handle friendship through a method on User? I say this because:

  1. The logic surrounding friendship is presumably in another app, so you might want to be explicit about calling a function defined in that app;
  2. Friendship is almost always a symmetric relation, so using a method on User leads to redundancy (a.is_friend_with(b) == b.is_friends_with(a)). If you later want to cache the result of the call, for instance, it makes sense to define a function which simply accepts user objects as arbitrarily ordered arguments; and,
  3. You probably don't want to do anything too fancy with HttpRequest or User as it's likely to confuse other developers.

My approach would be to define a manager method on whatever model represents friendship, and explicitly pass in users to that, like so: Friendship.objects.are_friends(other_user, request.user).

ozan
Thanks, great points. Why a manager method and not a classmethod on Friendship, i.e., Friendship.are_friends(a, b)?
Clay McClure
I've added some more detail to the question--would like to hear your thoughts. Thanks!
Clay McClure
Class method also makes sense. As does a utility function outside of the class. I was thinking a manager method as you might want to chain it after other manager methods (for instance filter) to check `are_friends` within a more limited queryset, but perhaps that is not necessary/desirable.
ozan
+1  A: 

You could create a proxy model of auth.User and add your is_friend method there. http://docs.djangoproject.com/en/dev/topics/db/models/#proxy-model-managers

As for the is_authenticated method, its a little simpler than you may think. The user context processor makes a special type of user available if they are not logged in, that is the AnonymousUser. This class always returns False when is_authenticated is called. Likewise the regular User class always returns True when is_authenticated is called.

In short, don't worry about the request object. If the current user is not logged in, the user variable available in your view will be using the AnonymousUser class and your is_friends method will not be found.

mountainswhim
The proxy model sounds like a good way to subclass User, thanks.
Clay McClure