Django: Предварительное заполнение дополнительных полей в Formset с помощью модели ManyToMany
У меня есть две модели с отношением ManyToMany (M2M). Для того чтобы иметь дополнительные поля в модели M2M, я определил модель through=
. Я попробовал настроить inlineformset_factory, используя parent=ChildModel
и model=ParentModel.parent_child.through
, как описано в этой теме pendant to inline formsets for many-to-many relations. Но это не решило мою проблему.
Как я могу получить доступ (т.е. предварительно заполнить) и обновить дополнительные поля модели M2M при использовании наборов форм?
models.py
class ParentModel(models.Model):
name = model.CharField()
parent_child = model.ManyToManyField(ChildModel, through='ParentChildModel')
class ChildModel(models.Model):
name = model.CharField()
class ParentChildModel(models.Model):
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
child = models.ForeignKey(ChildModel, on_delete=models.CASCADE)
extra_field_1 = models.CharField()
forms.py
class ChildForm(forms.ModelForm):
class Meta:
model = ChildModel
fields = '__all__'
ChildFormset = modelformset_factory(ChildModel,
form=ChildForm,
extra=0,
can_delete=True,
can_order=True,
)
Вам нужно создать набор форм с ParentChildModel
и экземпляром ChildModel
, а не просто использовать ChildModel
, поскольку он не сможет получить доступ к extra_field_1
.
В документации предлагается следующая структура inline-formset:
from django.forms import inlineformset_factory
ParentChildFormset = inlineformset_factory(ChildModel, ParentChildModel, ...)
child = ChildModel.objects.get(...)
formset = ParentChildFormset(instance=child)
https://docs.djangoproject.com/en/4.0/topics/forms/modelforms/#inline-formsets
Я нашел решение, установив ModelFormset на ChildModel. Для дополнительного поля я определил поле в form.py, которое я вручную заполняю, используя приведенный ниже код.
views.py
# get instances
parent_instance = Parent.objects.get(id=pk)
parent_children = parent_instance.parent_child.all()
parent_child_instance = ParentChildModel.objects.filter(parent=parent_instance)
# initializing & prepopulate forms
parent_form = ParentForm(request.POST or None, instance=parent_instance)
child_formset = ChildFormset(request.POST or None, queryset=parent_children)
for child_form in child_formset:
child_form.fields['extra_field_1'].initial = parent_child_instance.get(child=child_form.instance).extra_field_1