Django - Автоматическое заполнение отношения "многие-ко-многим-полям
Я пытаюсь сделать форму, которая автоматически заполняет отношение "многие-ко-многим" для моей модели пользователя. Цель состоит в том, чтобы иметь кнопку отправки, которая добавляет объект экземпляра представления (объект SingelWorkout) к отношению полей "многие ко многим" в моей пользовательской модели.
Представление точно отображает правильный объект, а форма отображается так, как было задумано в шаблоне. Я не хочу, чтобы пользователь видел выбор полей "многие ко многим". Кроме кнопки отправки, я стараюсь, чтобы вся логика происходила на бэкенде. Как я могу назначить экземпляр объекта полю в форме? Это должно происходить в views.py или forms.py?
Вот почему моя модель пользователя выглядит следующим образом:
class FitnessUser(AbstractUser):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField(max_length=60)
age_category = models.ForeignKey(
AgeGroup,
on_delete=models.CASCADE,
blank=True,
null=True
)
goal = models.IntegerField(default=1 ,choices=Purpose.choices)
weight = models.CharField(max_length=30)
height = models.CharField(max_length=30)
gender = models.ForeignKey(
Gender,
on_delete=models.CASCADE,
blank=True,
null=True
)
exercise_frequency = models.IntegerField(default=1 ,choices=Frequency.choices)
template_id = models.ForeignKey(
Workout_template,
on_delete=models.CASCADE,
blank=True,
null=True
)
completed_workouts = models.ManyToManyField(SingleWorkout)
def get_absolute_url(self):
return reverse('detail', args=[self.id])
Это моя форма в файле forms.py:
class CustomWorkoutChangeForm(UserChangeForm):
class Meta(UserChangeForm):
model = FitnessUser
fields = ('completed_workouts',)
exclude = ('completed_workouts',)
UserChangeForm.password = None
Вот как выглядит мой вид:
class WorkoutUpdateView(LoginRequiredMixin, UpdateView):
model = SingleWorkout
template_name = 'workout/daily_view.html'
form_class = CustomWorkoutChangeForm
success_url = reverse_lazy("template")
def get_context_data(self, **kwargs):
context = super(WorkoutUpdateView, self).get_context_data(**kwargs)
context['workout'] = SingleWorkout.objects.get(slug = self.kwargs['slug'])
return context
Мой html-шаблон выглядит следующим образом:
{{workout}}
<br>
workout:
<br>
{{ workout.exercise_1 }}
<br>
{{ workout.description_1 }}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Confirm">
</form>
Придумал решение. Я создал представление, которое получает объект экземпляра на основе url slug объекта, а также получает пользователя по его pk. Оттуда добавляет объект экземпляра в поле пользователя many to many, затем перенаправляет обратно на предыдущую страницу.
Создано новое представление:
def update_workout_data(request, slug):
workout = SingleWorkout.objects.get(slug=slug)
endUser = FitnessUser.objects.get(pk = request.user.pk)
endUser.completed_workouts.add(workout)
endUser.save()
return redirect(reverse('daily', kwargs={'slug':workout.slug}))
Обновленный внешний вид HTML. Я также изменил html и его детальное представление так, чтобы ссылка на обновление перенаправляла на отдельное представление обновления, в зависимости от необходимости добавить/удалить отношение.
{% block content %}
Daily View
<br>
{{exercise}}
<br>
workout:
<br>
<br>
{% if exercise.name in workouts %}
<h5>Workout Already Completed</h5>
<form method="POST" action="{% url 'remove' slug=exercise.slug %}">
{% csrf_token %}
<button type="submit">Reset</button>
</form>
{% else %}
<form method="POST" action="{% url 'update' slug=exercise.slug %}">
{% csrf_token %}
<button type="submit">Complete</button>
</form>
{% endif %}
{% endblock content %}
Обновленный детальный вид
def get_context_data(self, **kwargs):
context = super(WorkoutDetailView, self).get_context_data(**kwargs)
user = FitnessUser.objects.get(pk = self.request.user.pk)
context['exercise'] = SingleWorkout.objects.get(slug = self.kwargs['slug'])
context['workouts'] = {}
for workout in user.completed_workouts.all():
context['workouts'][workout.name] = workout
return context