Search code examples
djangodjango-modelsdjango-viewsdjango-authentication

Django Allow Interaction with Users Data Only


I'm adding some user profile behavior to a Django app, and as usual I would like to restrict users from only being able to interact with their own data. This SO Q&A is related to the process itself:

Django--- Allowing Users to only edit their profile

Is it enough to add the authenticated user id to the create, update, and delete queries? To reduce code duplication, I was thinking that I could write a mixin that would override get_object or get_queryset and intercept the query by adding the self.request.user.pk to filter the results?

Are there other efficient methods for doing this, or mixins from Django itself?

edit This is what i was thinking:

    class OwnersDataOnlyViewMixin(object):
    def get_object(self, queryset=None):
        if self.model == get_user_model():
            # user model, so pk of model should match self.request.user.pk
            return super().get_object(self.model.objects.filter(pk=self.request.user.pk))
        else:
            # different model
            try:
                # check for the 'user' field and filter on it if found
                user_field = self.model._meta.get_field('user')
                return super().get_object(self.model.objects.filter(user=self.request.user))
            except:
                # Mixin was used with model data not associated with a user
                raise self.model.DoesNotExist      

There are probably more flexible ways of doing this, and I'm open to suggestions to improve that.


Solution

  • For class based views you will most likely need to override the get_querset() method as the queryset returned by it will be used for getting the data for editing and deleting, therefore return something like MyModel.objects.filter(owner=self.request.user). Note that this will result in a 404 - "Not Found" response if the user is trying to access an object that doesnt belong to him.

    Upon creation of new objects you will mainly need to set request.user as the owner of the newly created object. This can be done with customizing the CreateView's form_valid() method:

    class MyCreateView(LoginRequiredMixin, generic.CreateView):
    
        def form_valid(self, form):
            form.instance.owner = self.request.user
            return super().form_valid(form)
    

    Depending on your model structure you can add this methods to a mixin and use them with the generic views.