Hiding user data of some users from others in django-generic-views

Viewed 65

My goal is to allow users to create their own Project instances with nested Task instances. Other users should not have access to data that they did not create. How can I do this correctly? I wrote a custom query set for ProjectListView, but I have problems with other views. Maybe there is a common solution for that case?

models.py

class Project(models.Model):
    project_name = models.CharField(max_length=150, default='')
    user = models.ForeignKey(get_user_model(), null=True, on_delete=models.CASCADE)

class Task(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    task_name = models.CharField(max_length=250, default='')
    is_done = models.BooleanField(default=False)

views.py

class ProjectListView(LoginRequiredMixin, ListView):
    model = Project
    context_object_name = 'projects'

    def get_queryset(self):
        return Project.objects.filter(user=self.request.user)

class ProjectCreateView(LoginRequiredMixin, CreateView):
    model = Project
    fields = ('project_name',)
    success_url = reverse_lazy('projects')

class ProjectUpdateView(LoginRequiredMixin, UpdateView):
    model = Project
    fields = ('project_name',)
    template_name = 'backend/project_update_form.html'
    success_url = reverse_lazy('projects')

class ProjectDeleteView(LoginRequiredMixin, DeleteView):
    model = Project
    success_url = reverse_lazy('projects')

class TaskCreateView(LoginRequiredMixin, CreateView):
    model = Task
    fields = '__all__'
    success_url = reverse_lazy('projects')

class TaskUpdateView(LoginRequiredMixin, UpdateView):
    model = Task
    fields = ('task_name', 'is_done',)
    template_name = 'backend/task_update_form.html'
    success_url = reverse_lazy('projects')

class TaskDeleteView(LoginRequiredMixin, DeleteView):
    model = Task
    success_url = reverse_lazy('projects')

As result:

class TaskCreateView(LoginRequiredMixin, TaskMixin, CreateView):
    model = Task
    fields = '__all__'
    success_url = reverse_lazy('projects')

    def get_form(self, *args, **kwargs):
        form_class = super().get_form(form_class=None)

        form_class.fields['project'].choices =\
            [(project.pk, project) for project in Project.objects.filter(user=self.request.user)]
        
        return form_class
1 Answers

You can move that custom queryset up to a mixin:

# mixins.py
class ProjectMixin(object):
    def get_queryset(self):
        return Project.objects.filter(user=self.request.user)

class TaskMixin(object):
    def get_queryset(self):
        return Task.objects.filter(project__user=self.request.user)

# views.py
class ProjectListView(LoginRequiredMixin, ProjectMixin, ListView):
    model = Project
    context_object_name = 'projects'

class ProjectCreateView(LoginRequiredMixin, ProjectMixin, CreateView):
    model = Project
    fields = ('project_name',)
    success_url = reverse_lazy('projects')

class ProjectUpdateView(LoginRequiredMixin, ProjectMixin, UpdateView):
    model = Project
    fields = ('project_name',)
    template_name = 'backend/project_update_form.html'
    success_url = reverse_lazy('projects')

class ProjectDeleteView(LoginRequiredMixin, ProjectMixin, DeleteView):
    model = Project
    success_url = reverse_lazy('projects')

class TaskCreateView(LoginRequiredMixin, TaskMixin, CreateView):
    model = Task
    fields = '__all__'
    success_url = reverse_lazy('projects')

class TaskUpdateView(LoginRequiredMixin, TaskMixin, UpdateView):
    model = Task
    fields = ('task_name', 'is_done',)
    template_name = 'backend/task_update_form.html'
    success_url = reverse_lazy('projects')

class TaskDeleteView(LoginRequiredMixin, TaskMixin, DeleteView):
    model = Task
    success_url = reverse_lazy('projects')
Related