user1100778
user1100778

Reputation: 63

Restricting access in django at the model level

I have a model and I'd like to restrict access to objects based on the authentication level of the user. Anonymous users may only see a subset of the objects while authorized users have access to all objects. Reading through the django book I find that I could use checks like, is_authenticated() in my views and implement my logic based on that condition. But I don't want these checks shotgun splattered all over my code, instead I'd like to be able to give my models some intelligence: the models should only make available the objects that are visible to the current user's permissions.

Here are a couple of the models I'm working with:

class Collection(models.Model):
    VISIBILITY_CHOICES = (
    ('P', 'Private'),
    ('SP', 'Semi-Private'),
    ('PUB', 'Public')
    )

    name = models.CharField(max_length=40)
    visibility = models.CharField(max_length=3, choices=VISIBILITY_CHOICES)
    category = models.CharField(max_length=50)


class Image(models.Model):
    image = models.ImageField(upload_to= get_upload_to)
    collection = models.ForeignKey(Collection)

An example of a query I make would be: collection_ids = Image.objects.values_list('collection',flat=True).distinct() -- In this case I'd only want to check against those collection ids that the user is authorized to view (i.e public/private/semi-private).

Is it possible or do I have to put authorization logic in my views?

Upvotes: 0

Views: 2648

Answers (2)

AdamKG
AdamKG

Reputation: 14046

Note that in the query example you give (Image.objects.values_list('collection',flat=True).distinct()), request is never mentioned - so how would that query be able to check the current user?

But that doesn't mean you have to do it in the views - you can add methods to the model itself, or even subclass QuerySet to add a method to check against the current request, like .filter(foo=bar).allowed_for_user(user).

See this answer:

https://stackoverflow.com/a/4576649/16361

Which links to an ancient blog post by yours truly, although I seem to have broken the link in that answer, sorry - the correct URL is:

EDIT: Remove a domain taken over by NSFW content and a dead link.

Also, just to make it clear - the code itself doesn't have to live in your views, but ultimately will need to involve the request object one way or another, so you will have to call it from your view.

Upvotes: 0

jdi
jdi

Reputation: 92559

Putting authentication onto the model is the wrong place for this logic. The views are exactly the correct place for this logic to live, which is why django provides the various auth decorators to protect views such as login_required()

The models job is to provide the layer of data access to the database. You would then create any number of views to visualize the data in the way you want. If you need anonymous views of data, create a view that checks if the user is authenticated, and formats the data appropriately.

Upvotes: 1

Related Questions