Search code examples
pythondjangopermissions

Django - object level premission and class based generic views


This is the model:

class Car(models.Model):
    user = models.ForeignKey(User, related_name='cars')
    name = models.CharField(max_length=64)

Url pattern goes something like this:

url(r'^car/(?P<pk>\d+)/$', login_required(CarDetails.as_view()), name='car_details)

And view:

class CarDetail(DetailView):
    context_object_name = 'car'
    template_name = 'my_app/car_details.html'
    model = models.Car

    def get_object(self, *args, **kwargs):
        car = super(CarDetail, self).get_object(*args, **kwargs)
        if car.user != self.request.user:
            raise PermissionDenied()
        else:
            return car

This works fine, but in every class I have to override get_object to prevent user to mess with someone else's objects. This includes editing and deleting for every model I have and this is serious violation of DRY principle.

Is there a better way to do this? Something like login_required decorator maybe?


Solution

  • What about definig base class (or mixin) and using inheritance?

    class CurUserOnlyDetailView(DetailView):
        def get_object(self, *args, **kwargs):
            obj = super(CurUserOnlyDetailView, self).get_object(*args, **kwargs)
            if obj.user != self.request.user:
                raise PermissionDenied()
            else:
                return obj
    
    class CarDetail(CurUserOnlyDetailView):
        context_object_name = 'car'
        template_name = 'my_app/car_details.html'
        model = models.Car
    
    # another view, no DRY violation
    class BikeDetail(CurUserOnlyDetailView):
        context_object_name = 'bike'
        template_name = 'my_app/bike_details.html'
        model = models.Bike