python - widgets - formularios django
¿Múltiples modelos en un solo django ModelForm? (5)
¿Es posible tener múltiples modelos incluidos en un único ModelForm
en django? Estoy tratando de crear un formulario de edición de perfil. Entonces necesito incluir algunos campos del modelo de Usuario y el modelo de Perfil de Usuario. Actualmente estoy usando 2 formularios como este
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 solo formulario o simplemente necesito crear un formulario y manejar la carga del db y guardarme a mí mismo?
Probablemente deberías echarle un vistazo a los formularios en línea . Los formularios en línea se usan cuando sus modelos están relacionados por una clave externa.
Puede mostrar ambos formularios en la plantilla dentro de un elemento <form>
html. Luego solo procesa los formularios por separado en la vista. Aún podrá usar form.save()
y no tendrá que procesar la carga de db y guardarse usted mismo.
En este caso, no debería necesitarlo, pero si va a utilizar formularios con los mismos nombres de campo, busque en el prefix
kwarg para los formularios django. (Respondí una pregunta al respecto here ).
Puede verificar mi respuesta aquí para un problema similar.
Habla sobre cómo combinar el registro y el perfil de usuario en un solo formulario, pero se puede generalizar a cualquier combinación de ModelForm.
Puedes intentar usar estos pedazos 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 teníamos el problema de que uno solo 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 basadas en clases genéricas. Defina el modelo, los campos y ahora también child_model y child_field, y luego puede ajustar los campos de ambos modelos en una etiqueta como 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.