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
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')