Django: обновление модели с текущим пользователем при изменении немодельного поля формы
Я создаю страницу, которая позволяет пользователям редактировать записи задач и связанных с ними активностей (у одной задачи может быть много активностей), все на одной странице. Я хочу позволить пользователю "принять" один или несколько видов деятельности, отметив соответствующее поле, и связать его пользовательскую запись с каждым видом деятельности через ForeignKey. Вот выдержки из моего кода...
models.py
from django.contrib.auth.models import User
class Task(models.Model):
category = models.CharField(max_length=300)
description = models.CharField(max_length=300)
class Activity(models.Model):
task = models.ForeignKey(Task, on_delete=models.CASCADE)
title = models.CharField(max_length=150)
notes = models.TextField(blank=True)
owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
Активность "владелец" связана с User из стандартной модели пользователя Django.
Я добавил дополнительное поле в определение формы для поля adopt - я не хочу добавлять его в модель, поскольку мне не нужно сохранять его после того, как оно выполнит свою работу.
forms.py
class ActivityForm(forms.ModelForm):
adopt = forms.BooleanField(required=False)
class Meta:
model = Activity
fields = '__all__'
views.py
def manage_task(request, pk):
task = Task.objects.get(pk = pk)
TaskInlineFormSet = inlineformset_factory(Task, Activity,
form = ActivityForm)
if request.method == "POST":
form = TaskForm(request.POST, instance = task)
formset = TaskInlineFormSet(request.POST, instance = task)
if form.has_changed() and form.is_valid():
form.save()
if formset.has_changed() and formset.is_valid():
## ? DO SOMETHING HERE ? ##
formset.save()
return redirect('manage_task',pk=task.id)
else:
form = TaskForm(instance = task)
formset = TaskInlineFormSet(instance = task)
context = {'task': task, 'task_form': form, 'formset': formset}
return render(request, 'tasks/manage_task.html', context)
Когда поле adopt отмечено на форме, я хочу иметь возможность установить поле owner в этой форме на текущего пользователя до того, как связанный экземпляр модели будет обновлен и сохранен.
Я просто не могу понять, как это сделать - если бы это была одна форма (а не InlineFormSet), я думаю, я мог бы поместить код в представление, чтобы изменить значение владельца в поле формы перед сохранением (я не пробовал этого). Или попробовать save(commit = False) и обновить экземпляр модели, а затем save() его.
Может быть, мне нужно итеративно перебрать набор форм в коде представления и попробовать один из этих вариантов, когда я найду тот, у которого adopt=True?
When the adopt field is ticked on the form, I want to be able to set the owner field in that form to the current user before the associated model instance is updated and saved.
formset = TaskInlineFormSet(request.POST, instance = task)
if formset.adopt:
# If True
formset.user = request.user
formset.save()
I think I could put code in the view to change the owner value in the form field before it was saved (I haven't tried this).
Вам стоит попробовать.
Я не доволен этим решением, но оно работает. Я перебираю формы и изменяю экземпляр объекта, если мое поле adopt установлено.
views.py
def manage_task(request, pk):
task = Task.objects.get(pk = pk)
TaskInlineFormSet = inlineformset_factory(Task, Activity,
form = ActivityForm)
if request.method == "POST":
form = TaskForm(request.POST, instance = task)
formset = TaskInlineFormSet(request.POST, instance = task)
if form.has_changed() and form.is_valid():
form.save()
if formset.has_changed() and formset.is_valid():
## HERE'S WHAT I ADDED ##
for form in formset:
if form.cleaned_data['adopt'] is True:
form.instance.owner = request.user
## END OF ADDITIONS ##
formset.save()
## return redirect('manage_task',pk=task.id) # CHANGED THIS BECAUSE I WASN'T RETURNG ERRORS!
if not form.errors and not formset.total_error_count():
return redirect('manage_task',pk=task.id)
else:
form = TaskForm(instance = task)
formset = TaskInlineFormSet(instance = task)
context = {'task': task, 'task_form': form, 'formset': formset}
return render(request, 'tasks/manage_task.html', context)
Хотелось бы найти в документации больше информации о том, как работает сохранение формы, но, думаю, мне придется заглянуть в код, если мне нужно больше деталей.