问题
After reading the permission Django documentation, I'm still confused. I'd like to prevent access for user to edit or delete objects they didn't own. I dit it this way and it works:
In views.py:
def deleteReward(request, reward_id):
reward = get_object_or_404(Reward, pk=reward_id)
if reward.owner.user != request.user: # if the user linked to the reward is not the current one
raise Exception("This reward is not yours, you can't delete it !")
#...
But I think this isn't clean and DRY for two reasons:
In each editStuff and deleteStuff views, I'll have to write the same portion of code.
I'm currently writing an API with Tastypie, and if the permission logic is in a view, I won't be able to re-use it. The best way to deals with seems to be to map the API permission with the Django permissions (but the code I wrote in my view has nothing to do with permissions).
Could you help me to find the right way to do? Thanks a lot.
回答1:
Here is my working example.
1) QuerySet
class PermissionQuerySet(models.query.QuerySet):
def editable_by(self, user):
return self.filter(user=user)
def viewable_by(self, user):
return self.filter(user=user)
2) Managers
class PermissionManager(models.Manager):
def get_query_set(self):
return PermissionQuerySet(self.model)
def editable_by(self, user, *args):
return self.get_query_set().editable_by(user, *args)
def viewable_by(self, user, *args):
return self.get_query_set().viewable_by(user, *args)
3) Models
class MyModel(models.Model):
...
objects = PermissionManager()
This approach works perfectly with class based views. I see you using TastyPie. I never used it before but it seems it's uses class based views too.
This is working sample:
class MyUpdateView(UpdateView):
def post(self, request, *args, **kwargs):
self.request = request
super(MyUpdateView, self).post(request, *args, **kwargs)
def get_query_set(self):
queryset = super(MyUpdateView, self).get_query_set()
queryset = queryset.editable_by(self.request.user)
if not queryset.exists():
raise Exception("This reward is not yours, you can't delete it !")
return queryset
I think you can imagine how to use this approach in CreateView, DeleteView. And i think it is easy to implement this in TastyPie.
回答2:
Pass an additional parameter to get_object_or_404
:
reward = get_object_or_404(Reward, pk=reward_id, owner=request.user)
来源:https://stackoverflow.com/questions/22178928/django-a-more-dry-way-to-prevent-edit-delete-of-objects