Django Permissions traversal across multiple foreign keys

Viewed 31

I have 4 core entity models:

  • User
    • Can be an Owner or Participant on a Collection
  • Collection
  • Recipe
    • A recipe has a foreign key to a collection
  • Steps
    • A step has a foreign key to a recipe

In order to enable the above, I think I need a model for each of them as well as a model (let's call it CollectionContributor) with the following fields:

  • contributor - this would be a foreign key to the user model
  • collection - this would be a foreign key to the collection

On the Collection then, I'd add a many to many field that looks like this:

class Collection(models.Model):
    ...
    contributors = models.ManyToManyField(settings.AUTH_USER_MODEL, through='CollectionContributor')

Now, let's say I want to provide a page that lists all "step" across all recipes. If I want to limit that view to those steps that are part of recipes that are part of collections that the user has access to, how would I do that. Essentially, how can I manage permissions that require traversal of multiple foreign keys?

I assumed it might be something like the following. But it seems terribly inefficient, and could lead to performance issues if entities go several layers deep. Is this the "right" way to do this?

def someViewOfSteps(request):
    collections = models.Collection.objects.filter(Q(contributors__in=request.user))
    recipes = models.Recipe.objects.filter(Q(collection__in=collections))
    steps = models.Step.objects.filter(Q(recipe__in==recipe))
    return steps

Is that right?

1 Answers

You can query with:

def someViewOfSteps(request):
    return Step.objects.filter(
        recipe__collection__contributors=request.user
    )

This will use JOINs instead of … IN … with subqueries, which tend to be less efficient, especially in MySQL.

Related