views:

22

answers:

1

Users on a webapp I'm building have multiple objects that are "theirs" Let's pretend the object is called Toy.

I want them to be able to set privacy options for their Toys so they can set the following visibility options:

  1. Friends of friends
  2. Friends
  3. Only allow a defined set of people
  4. Friends only, but deny a set of people (to keep it a secret from some people)

So say I have the models like so:

class User(models.Model): # actually a profile but simplifying
    friends = models.ManyToManyField(User, through='Friendship')

class Toy(models.Model):
    owner = models.ForeignKey(User)

I'm struggling to see how to layer on the permissions data and logic.

I could add a permission_state variable that stored the above choice and then have a m2m for options #3 and #4, or have separate m2ms for DENY and ALLOW.

But given a User, how would I filter for all toys that the user could see without doing umpteen different queries? I ideally want to generate a list of Toy objects in one trip to the database.

Or am I approaching this the wrong way?

+1  A: 

I had to solve a similar problem once. I didn't find any fancy solution, for I didn't need something robust and clean. Here's what I did :

I created a intermediate model :

class ToyPermission(models.Model):
    toy = ForeignKey(Toy)
    level = models.CharField(max_length=100, choices=(
        'f_of_f', 'Friends of friends',
        ...
    ))
    allowed_users = ...
    denied_users = ...

Then I wrote some view decorators for views that have the following signature :

def some_view(request, toy):
    #the code

These decorators check the permissions, and then set some variables, either directly in the extra_context, or a special kwarg.

This solution is not perfect at all,... but it might help you !

However, now that I re-read your question, I am not sure I answer exactly to what you asked :

But given a User, how would I filter for all toys that the user could see

Do you mean, like on facebook : when a user A visits a user B's page, you want to display only toys from user B that are allowed to user A ?

sebpiq
That certainly fits the bill for finding if one user can view a single `Toy` but per your re-read, if you're browsing as `User A` and you want to see all `User B`'s `Toy`s, how do I form that query to get a list of `Toy` objects without iterating each and pulling in the permissions and then excluding?
Oli
You could probably work it out, with something ugly like : if is_userA_friend_of_friend:ToyPermission.objects.filter(toy__in=userA.toy_set).filter(Q(level='f_of_f'), Q(allowed_user__contains=userA), ~Q(denied_user__contains=userA)). ... .select_related() . BUT I asmit once again that this is far from being a perfect solution !
sebpiq