Django: как отфильтровать поле формы на основе отношения "многие ко многим"?
В настоящее время, когда пользователь создает задачу, он может назначить ее всем пользователям. Я хочу, чтобы они могли назначать задачу только на основе членов проекта. Мне кажется, что концепция, которую я имею сейчас, работает, но мне нужно заменить ????.
projects/models.py
class Project(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
members = models.ManyToManyField(USER_MODEL, related_name="projects")
tasks/models.py
class Task(models.Model):
name = models.CharField(max_length=200)
start_date = models.DateTimeField()
due_date = models.DateTimeField()
is_completed = models.BooleanField(default=False)
project = models.ForeignKey(
"projects.Project", related_name="tasks", on_delete=models.CASCADE
)
assignee = models.ForeignKey(
USER_MODEL, null=True, related_name="tasks", on_delete=models.SET_NULL
)
tasks/views.py
class TaskCreateView(LoginRequiredMixin, CreateView):
model = Task
template_name = "tasks/create.html"
# fields = ["name", "start_date", "due_date", "project", "assignee"]
form_class = TaskForm
def get_form_kwargs(self):
kwargs = super(TaskCreateView, self).get_form_kwargs()
kwargs["user"] = self.request.user
kwargs["project_members"] = ??????????
return kwargs
tasks/forms.py
class TaskForm(ModelForm):
class Meta:
model = Task
fields = ["name", "start_date", "due_date", "project", "assignee"]
def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
project_members = kwargs.pop("project_members")
super(TaskForm, self).__init__(*args, **kwargs)
self.fields["project"].queryset = Project.objects.filter(members=user)
self.fields["assignee"].queryset = Project.objects.filter(
members=?????????
)
Проблема здесь в том, что ваша задача не знает, какие члены являются релевантными для включения в качестве назначенных, пока вы не выбрали проект, к которому принадлежит задача, а проект и назначенный выбираются в одной форме, поэтому Django еще не знает, кто является релевантным.
Самый простой способ справиться с этим - убедиться, что вызов создания задачи связан с проектом, для которого она будет создана - например,
Обновите ваши URL-адреса для работы с ID проекта
Path('create-task/<int:project_id>', TaskCreateView.as_view(), name='create_task')
Обновить представление
class TaskCreateView(LoginRequiredMixin, CreateView):
model = Task
template_name = "tasks/create.html"
# fields = ["name", "start_date", "due_date", "assignee"]
#NB: I have remove project from the field list, you may need to do the same in your form as it is handled elsewhere
form_class = TaskForm
def get_form(self, *args, **kwargs):
form = super(TaskForm, self).get_form(*args, **kwargs)
form.fields['assignee'].queryset = Project.members.filter(project_id = self.kwargs['project_id'])
def form_valid(self, form):
form.instance.project_id = project.self.kwargs['project_id']
return super(CreateTask, self).form_valid(form)
Добавить ссылки
<a href="{% url create_task project_id %}">Create Task for this project</a>
Это создаст ссылку на странице подробностей проекта или под проектом в представлении списка на "создать задачу для этого проекта", перенося информацию о проекте в представление через URL. В противном случае вам придется прибегнуть к более сложным вызовам ajax, которые будут динамически заполнять список потенциальных назначенцев на основе выбора в выпадающем списке проекта