Несколько моделей в одной модели Django ModelForm?
Возможно ли иметь несколько моделей, включенных в один ModelForm
в django? Я пытаюсь создать форму редактирования профиля. Поэтому мне нужно включить некоторые поля в модель User Model и модели UserProfile. В настоящее время я использую 2 формы, такие как
class UserEditForm(ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name")
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
fields = ("middle_name", "home_phone", "work_phone", "cell_phone")
Есть ли способ объединить их в одну форму или мне просто нужно создать форму и обработать загрузку db и сохранить себя?
Ответы
Ответ 1
Вы можете просто показать обе формы в шаблоне внутри одного элемента <form>
html. Затем просто обрабатывайте формы отдельно в представлении. Вы по-прежнему сможете использовать form.save()
и не должны обрабатывать загрузку db и сохранять себя.
В этом случае вам это не понадобится, но если вы собираетесь использовать формы с одинаковыми именами полей, просмотрите prefix
kwarg для форм django. (Я ответил на вопрос об этом здесь).
Ответ 2
Вы можете попробовать использовать эти фрагменты кода:
class CombinedFormBase(forms.Form):
form_classes = []
def __init__(self, *args, **kwargs):
super(CombinedFormBase, self).__init__(*args, **kwargs)
for f in self.form_classes:
name = f.__name__.lower()
setattr(self, name, f(*args, **kwargs))
form = getattr(self, name)
self.fields.update(form.fields)
self.initial.update(form.initial)
def is_valid(self):
isValid = True
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
if not form.is_valid():
isValid = False
# is_valid will trigger clean method
# so it should be called after all other forms is_valid are called
# otherwise clean_data will be empty
if not super(CombinedFormBase, self).is_valid() :
isValid = False
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
self.errors.update(form.errors)
return isValid
def clean(self):
cleaned_data = super(CombinedFormBase, self).clean()
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
cleaned_data.update(form.cleaned_data)
return cleaned_data
Пример использования:
class ConsumerRegistrationForm(CombinedFormBase):
form_classes = [RegistrationForm, ConsumerProfileForm]
class RegisterView(FormView):
template_name = "register.html"
form_class = ConsumerRegistrationForm
def form_valid(self, form):
# some actions...
return redirect(self.get_success_url())
Ответ 3
Вероятно, вам стоит взглянуть на встроенные формы. Встроенные формы используются, когда ваши модели связаны с внешним ключом.
Ответ 4
Вы можете проверить мой ответ здесь для аналогичной проблемы.
В нем рассказывается о том, как объединить регистрацию и профиль пользователя в одну форму, но ее можно обобщить на любую комбинацию ModelForm.
Ответ 5
erikbwork, и у меня была проблема, что можно включить только одну модель в общий классный подход. Я нашел аналогичный подход к нему, как Мяо, но более модульный.
Я написал Mixin, чтобы вы могли использовать все общие представления класса. Определите модель, поля и теперь также child_model и child_field - и затем вы можете обернуть поля обеих моделей в тег, как описывает Zach.
class ChildModelFormMixin:
''' extends ModelFormMixin with the ability to include ChildModelForm '''
child_model = ""
child_fields = ()
child_form_class = None
def get_child_model(self):
return self.child_model
def get_child_fields(self):
return self.child_fields
def get_child_form(self):
if not self.child_form_class:
self.child_form_class = model_forms.modelform_factory(self.get_child_model(), fields=self.get_child_fields())
return self.child_form_class(**self.get_form_kwargs())
def get_context_data(self, **kwargs):
if 'child_form' not in kwargs:
kwargs['child_form'] = self.get_child_form()
return super().get_context_data(**kwargs)
def post(self, request, *args, **kwargs):
form = self.get_form()
child_form = self.get_child_form()
# check if both forms are valid
form_valid = form.is_valid()
child_form_valid = child_form.is_valid()
if form_valid and child_form_valid:
return self.form_valid(form, child_form)
else:
return self.form_invalid(form)
def form_valid(self, form, child_form):
self.object = form.save()
save_child_form = child_form.save(commit=False)
save_child_form.course_key = self.object
save_child_form.save()
return HttpResponseRedirect(self.get_success_url())
Пример использования:
class ConsumerRegistrationUpdateView(UpdateView):
model = Registration
fields = ('firstname', 'lastname',)
child_model = ConsumerProfile
child_fields = ('payment_token', 'cart',)
Или с ModelFormClass:
class ConsumerRegistrationUpdateView(UpdateView):
model = Registration
fields = ('firstname', 'lastname',)
child_model = ConsumerProfile
child_form_class = ConsumerProfileForm
Готово. Надежда, которая помогает кому-то.