Múltiples modelos en un solo ModelForm django?

¿Es posible tener varios modelos incluidos en un solo ModelForm en django? Estoy tratando de crear un formulario de edición de perfil. Así que necesito incluir algunos campos del modelo de usuario y el modelo de perfil de usuario. Actualmente estoy usando 2 formas como esta

 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") 

¿Hay alguna forma de consolidarlos en un formulario o solo necesito crear un formulario y manejar la carga y el ahorro de la base de datos?

Solo puede mostrar ambos formularios en la plantilla dentro de un elemento html

. Luego simplemente procesa los formularios por separado en la vista. Aún podrá usar form.save() y no tendrá que procesar la carga y guardado de la base de datos.

En este caso, no deberías necesitarlo, pero si vas a utilizar formularios con los mismos nombres de campo, busca en el prefix kwarg para formularios django. (Respondí una pregunta al respecto aquí ).

Puedes intentar usar estas piezas de código:

 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 

Ejemplo de uso:

 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()) 

erikbwork y yo tuvimos el problema de que solo se puede incluir un modelo en una vista genérica basada en la clase. Encontré una forma similar de abordarlo como Miao, pero más modular.

Escribí un Mixin para que pueda usar todas las vistas genéricas basadas en clase. Defina el modelo, los campos y ahora también child_model y child_field, y luego puede envolver los campos de ambos modelos en una etiqueta como la que describe 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()) 

Ejemplo de uso:

 class ConsumerRegistrationUpdateView(UpdateView): model = Registration fields = ('firstname', 'lastname',) child_model = ConsumerProfile child_fields = ('payment_token', 'cart',) 

O con ModelFormClass:

 class ConsumerRegistrationUpdateView(UpdateView): model = Registration fields = ('firstname', 'lastname',) child_model = ConsumerProfile child_form_class = ConsumerProfileForm 

Hecho. Espero que ayude a alguien.

Probablemente debería echar un vistazo a los formularios en línea . Los conjuntos de formularios en línea se utilizan cuando sus modelos están relacionados por una clave externa.

Puede comprobar mi respuesta aquí para un problema similar.

Habla sobre cómo combinar el registro y el perfil de usuario en un formulario, pero se puede generalizar a cualquier combinación de ModelForm.