问题
I have a particular model and that model has finegrained access settings. Something like:
class Document(models.Model):
...
access = models.ManyToManyField(Group)
Groups consist of particular tags, and those tags are linked to users. Long story short, one way or another the documents are only accessible by particular users. It is very important that this check does not slip through the cracks. So I can see a number of options. One is that every time I access a Document, I add the check:
Document.objects.filter(access__group__tag__user=request.user)
But there are two drawbacks: a) I query the documents model > 100 times in my views so I will have a LOT of repeated code, and b) it's quite likely that someone will at some point forget to add this restriction in, leaving documents exposed.
So I am thinking that overwriting the objects() makes most sense, through a custom manager. That way I don't duplicate code and I don't risk forgetting to do this.
class HasAccessManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(access__group__tag__user=request.user)
class Document(models.Model):
...
access = models.ManyToManyField(Group)
objects = HasAccessManager()
However, the problem becomes that request is not accessible there:
name 'request' is not defined
How to solve this? Or are there better solutions?
回答1:
Create a mixin that your views inherit from. This will prevent having duplicated code everywhere. You'll want to write unit tests to make sure your views are locked down appropriately.
class HasAccessMixin(object):
def get_queryset(self):
qs = super().get_queryset()
# you can still leverage a custom model manager here if you want
# qs = qs.custom_method(access__group__tag__user=self.request.user)
qs = queryset.filter(access__group__tag__user=self.request.user)
return qs
class SomeListView(HasAccessMixin, ListView):
...
class SomeDetailView(HasAccessMixin, DetailView):
...
来源:https://stackoverflow.com/questions/58039448/limiting-access-to-objects-in-django