Можно ли включить несколько моделей в одну ModelForm
в django? Я пытаюсь создать форму редактирования профиля. Поэтому мне нужно , чтобы включить некоторые поля из модели пользователя и модели 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")
Есть ли способ объединить их в одну форму или мне просто нужно создать форму и обрабатывать загрузку базы данных и сохранение себя?
python
django
django-forms
Джейсон Уэбб
источник
источник
Ответы:
Вы можете просто показать обе формы в шаблоне внутри одного
<form>
элемента html. Затем просто обработайте формы отдельно в представлении. Вы по-прежнему сможете использоватьform.save()
и не будете обрабатывать загрузку и сохранение базы данных самостоятельно.В этом случае он вам не понадобится, но если вы собираетесь использовать формы с одинаковыми именами полей, посмотрите
prefix
kwarg для форм django. (Я ответил на вопрос об этом здесь ).источник
<form>
элемент?FormView
aform_class
назначается только один .TemplateView
создайте подкласс и реализуйте ту же логику, что и FormView, но с несколькими формами.Вы можете попробовать использовать следующие фрагменты кода:
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())
источник
admin.E016) The value of 'form' must inherit from 'BaseModelForm'.
UpdateView
?У меня и у erikbwork была проблема, заключающаяся в том, что в общее представление на основе классов можно включить только одну модель. Я нашел такой же подход, как Мяо, но более модульный.
Я написал Mixin, чтобы вы могли использовать все общие представления на основе классов. Определите модель, поля, а теперь еще и child_model и child_field - а затем вы можете заключить поля обеих моделей в тег, как описывает Зак.
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
Выполнено. Надеюсь, это кому-то поможет.
источник
save_child_form.course_key = self.object
что.course_key
?return self.child_form_class(**self.get_form_kwargs())
но получает неправильный экземпляр моделиkwargs['instance']
, например, экземпляр - это основная модель, а не дочерняя модель. Чтобы исправить это, вам нужно сначала сохранить kwargs в переменной, аkwargs = self.get_form_kwargs()
затем обновитьkwargs['initial']
правильный экземпляр модели перед вызовомreturn self.child_form_class(**kwargs)
. В моем случае это было,kwargs['instance'] = kwargs['instance'].profile
если в этом есть смысл.model_forms
?Вам, вероятно, стоит взглянуть на встроенные наборы форм . Встроенные наборы форм используются, когда ваши модели связаны внешним ключом.
источник
Вы можете проверить мой ответ здесь на аналогичную проблему.
В нем рассказывается о том, как объединить регистрацию и профиль пользователя в одну форму, но его можно обобщить на любую комбинацию ModelForm.
источник
Я использовал Джанго betterforms «S многообразный и MultiModelForm в моем проекте. Однако код можно улучшить. Например, он зависит от django.six, который не поддерживается в 3. +, но все это легко исправить.
Этот вопрос несколько раз появлялся в StackOverflow, поэтому я думаю, что пора найти стандартизированный способ справиться с этим.
источник