widgets tipos personalizados formularios fields ejemplos avanzados python django forms

python - tipos - Manera correcta de manejar múltiples formularios en una página en Django



post django (9)

Tengo una página de plantilla esperando dos formularios. Si solo uso un formulario, las cosas están bien como en este ejemplo típico:

if request.method == ''POST'': form = AuthorForm(request.POST,) if form.is_valid(): form.save() # do something. else: form = AuthorForm()

Sin embargo, si deseo trabajar con varios formularios, ¿cómo puedo dejar que la vista sepa que estoy enviando solo uno de los formularios y no el otro (es decir, sigue siendo request.POST pero solo quiero procesar el formulario sucedió)?

Esta es la solución basada en la respuesta donde waitingphrase y bannedphrase son los nombres de los botones de envío para las diferentes formas, y expectedphraseform y bannedphraseform son los formularios.

if request.method == ''POST'': if ''bannedphrase'' in request.POST: bannedphraseform = BannedPhraseForm(request.POST, prefix=''banned'') if bannedphraseform.is_valid(): bannedphraseform.save() expectedphraseform = ExpectedPhraseForm(prefix=''expected'') elif ''expectedphrase'' in request.POST: expectedphraseform = ExpectedPhraseForm(request.POST, prefix=''expected'') if expectedphraseform.is_valid(): expectedphraseform.save() bannedphraseform = BannedPhraseForm(prefix=''banned'') else: bannedphraseform = BannedPhraseForm(prefix=''banned'') expectedphraseform = ExpectedPhraseForm(prefix=''expected'')


Aquí hay una manera simple de manejar lo anterior.

En la plantilla Html ponemos mensaje

<form action="/useradd/addnewroute/" method="post" id="login-form">{% csrf_token %} <!-- add details of form here--> <form> <form action="/useradd/addarea/" method="post" id="login-form">{% csrf_token %} <!-- add details of form here--> <form>

En vista

def addnewroute(request): if request.method == "POST": # do something def addarea(request): if request.method == "POST": # do something

En URL, brinde la información necesaria, como

urlpatterns = patterns('''', url(r''^addnewroute/$'', views.addnewroute, name=''addnewroute''), url(r''^addarea/'', include(''usermodules.urls'')),


Esto es un poco tarde, pero esta es la mejor solución que encontré. Usted crea un diccionario de búsqueda para el nombre del formulario y su clase, también debe agregar un atributo para identificar el formulario, y en sus vistas debe agregarlo como un campo oculto, con form.formlabel .

# form holder form_holder = { ''majeur'': { ''class'': FormClass1, }, ''majsoft'': { ''class'': FormClass2, }, ''tiers1'': { ''class'': FormClass3, }, ''tiers2'': { ''class'': FormClass4, }, ''tiers3'': { ''class'': FormClass5, }, ''tiers4'': { ''class'': FormClass6, }, } for key in form_holder.keys(): # If the key is the same as the formlabel, we should use the posted data if request.POST.get(''formlabel'', None) == key: # Get the form and initate it with the sent data form = form_holder.get(key).get(''class'')( data=request.POST ) # Validate the form if form.is_valid(): # Correct data entries messages.info(request, _(u"Configuration validée.")) if form.save(): # Save succeeded messages.success( request, _(u"Données enregistrées avec succès.") ) else: # Save failed messages.warning( request, _(u"Un problème est survenu pendant l''enregistrement " u"des données, merci de réessayer plus tard.") ) else: # Form is not valid, show feedback to the user messages.error( request, _(u"Merci de corriger les erreurs suivantes.") ) else: # Just initiate the form without data form = form_holder.get(key).get(''class'')(key)() # Add the attribute for the name setattr(form, ''formlabel'', key) # Append it to the tempalte variable that will hold all the forms forms.append(form)

Espero que esto ayude en el futuro.


Las vistas basadas en clases de Django proporcionan un FormView genérico, pero a todos los efectos está diseñado para manejar solo un formulario.

Una forma de manejar múltiples formularios con la misma URL de acción objetivo utilizando las vistas genéricas de Django es ampliar el ''TemplateView'' como se muestra a continuación; Utilizo este enfoque con la frecuencia suficiente para convertirlo en una plantilla IDE de Eclipse.

class NegotiationGroupMultifacetedView(TemplateView): ### TemplateResponseMixin template_name = ''offers/offer_detail.html'' ### ContextMixin def get_context_data(self, **kwargs): """ Adds extra content to our template """ context = super(NegotiationGroupDetailView, self).get_context_data(**kwargs) ... context[''negotiation_bid_form''] = NegotiationBidForm( prefix=''NegotiationBidForm'', ... # Multiple ''submit'' button paths should be handled in form''s .save()/clean() data = self.request.POST if bool(set([''NegotiationBidForm-submit-counter-bid'', ''NegotiationBidForm-submit-approve-bid'', ''NegotiationBidForm-submit-decline-further-bids'']).intersection( self.request.POST)) else None, ) context[''offer_attachment_form''] = NegotiationAttachmentForm( prefix=''NegotiationAttachment'', ... data = self.request.POST if ''NegotiationAttachment-submit'' in self.request.POST else None, files = self.request.FILES if ''NegotiationAttachment-submit'' in self.request.POST else None ) context[''offer_contact_form''] = NegotiationContactForm() return context ### NegotiationGroupDetailView def post(self, request, *args, **kwargs): context = self.get_context_data(**kwargs) if context[''negotiation_bid_form''].is_valid(): instance = context[''negotiation_bid_form''].save() messages.success(request, ''Your offer bid #{0} has been submitted.''.format(instance.pk)) elif context[''offer_attachment_form''].is_valid(): instance = context[''offer_attachment_form''].save() messages.success(request, ''Your offer attachment #{0} has been submitted.''.format(instance.pk)) # advise of any errors else messages.error(''Error(s) encountered during form processing, please review below and re-submit'') return self.render_to_response(context)

La plantilla html tiene el siguiente efecto:

... <form id=''offer_negotiation_form'' class="content-form" action=''./'' enctype="multipart/form-data" method="post" accept-charset="utf-8"> {% csrf_token %} {{ negotiation_bid_form.as_p }} ... <input type="submit" name="{{ negotiation_bid_form.prefix }}-submit-counter-bid" title="Submit a counter bid" value="Counter Bid" /> </form> ... <form id=''offer-attachment-form'' class="content-form" action=''./'' enctype="multipart/form-data" method="post" accept-charset="utf-8"> {% csrf_token %} {{ offer_attachment_form.as_p }} <input name="{{ offer_attachment_form.prefix }}-submit" type="submit" value="Submit" /> </form> ...


Necesitaba formularios múltiples que se validen independientemente en la misma página. Los conceptos clave que me faltaban eran 1) usar el prefijo del formulario para el nombre del botón de envío y 2) una forma ilimitada no desencadena la validación. Si ayuda a alguien más, aquí está mi ejemplo simplificado de dos formularios AForm y BForm usando TemplateView basado en las respuestas de @ adam-nelson y @ daniel-sokolowski y comentario de @zeraien ( https://.com/a/17303480/2680349 ):

# views.py def _get_form(request, formcls, prefix): data = request.POST if prefix in request.POST else None return formcls(data, prefix=prefix) class MyView(TemplateView): template_name = ''mytemplate.html'' def get(self, request, *args, **kwargs): return self.render_to_response({''aform'': AForm(prefix=''aform_pre''), ''bform'': BForm(prefix=''bform_pre'')}) def post(self, request, *args, **kwargs): aform = _get_form(request, AForm, ''aform_pre'') bform = _get_form(request, BForm, ''bform_pre'') if aform.is_bound and aform.is_valid(): # Process aform and render response elif bform.is_bound and bform.is_valid(): # Process bform and render response return self.render_to_response({''aform'': aform, ''bform'': bform}) # mytemplate.html <form action="" method="post"> {% csrf_token %} {{ aform.as_p }} <input type="submit" name="{{aform.prefix}}" value="Submit" /> {{ bform.as_p }} <input type="submit" name="{{bform.prefix}}" value="Submit" /> </form>


Quería compartir mi solución donde Django Forms no está siendo utilizado. Tengo múltiples elementos de formulario en una sola página y quiero usar una sola vista para administrar todas las solicitudes POST de todos los formularios.

Lo que hice fue introducir una etiqueta de entrada invisible para poder pasar un parámetro a las vistas y verificar qué formulario se envió.

<form method="post" id="formOne"> {% csrf_token %} <input type="hidden" name="form_type" value="formOne"> ..... </form> ..... <form method="post" id="formTwo"> {% csrf_token %} <input type="hidden" name="form_type" value="formTwo"> .... </form>

views.py

def handlemultipleforms(request, template="handle/multiple_forms.html"): """ Handle Multiple <form></form> elements """ if request.method == ''POST'': if request.POST.get("form_type") == ''formOne'': #Handle Elements from first Form elif request.POST.get("form_type") == ''formTwo'': #Handle Elements from second Form


Si está utilizando el enfoque con vistas basadas en clases y diferentes atributos de "acción" me refiero

Ponga diferentes URL en la acción para los dos formularios. Luego tendrá dos funciones de visualización diferentes para tratar las dos formas diferentes.

Puede manejar fácilmente los errores de diferentes formas utilizando el método get_context_data sobrecargado, por ejemplo:

views.py:

class LoginView(FormView): form_class = AuthFormEdited success_url = ''/'' template_name = ''main/index.html'' def dispatch(self, request, *args, **kwargs): return super(LoginView, self).dispatch(request, *args, **kwargs) .... def get_context_data(self, **kwargs): context = super(LoginView, self).get_context_data(**kwargs) context[''login_view_in_action''] = True return context class SignInView(FormView): form_class = SignInForm success_url = ''/'' template_name = ''main/index.html'' def dispatch(self, request, *args, **kwargs): return super(SignInView, self).dispatch(request, *args, **kwargs) ..... def get_context_data(self, **kwargs): context = super(SignInView, self).get_context_data(**kwargs) context[''login_view_in_action''] = False return context

modelo:

<div class="login-form"> <form action="/login/" method="post" role="form"> {% csrf_token %} {% if login_view_in_action %} {% for e in form.non_field_errors %} <div class="alert alert-danger alert-dismissable"> {{ e }} <a class="panel-close close" data-dismiss="alert">×</a> </div> {% endfor %} {% endif %} ..... </form> </div> <div class="signin-form"> <form action="/registration/" method="post" role="form"> {% csrf_token %} {% if not login_view_in_action %} {% for e in form.non_field_errors %} <div class="alert alert-danger alert-dismissable"> {{ e }} <a class="panel-close close" data-dismiss="alert">×</a> </div> {% endfor %} {% endif %} .... </form> </div>



Un método para futuras referencias es algo como esto. bannedphraseform es la primera forma y expectedphraseform es la segunda. Si se golpea al primero, se salta el segundo (lo cual es una suposición razonable en este caso):

if request.method == ''POST'': bannedphraseform = BannedPhraseForm(request.POST, prefix=''banned'') if bannedphraseform.is_valid(): bannedphraseform.save() else: bannedphraseform = BannedPhraseForm(prefix=''banned'') if request.method == ''POST'' and not bannedphraseform.is_valid(): expectedphraseform = ExpectedPhraseForm(request.POST, prefix=''expected'') bannedphraseform = BannedPhraseForm(prefix=''banned'') if expectedphraseform.is_valid(): expectedphraseform.save() else: expectedphraseform = ExpectedPhraseForm(prefix=''expected'')


ver:

class AddProductView(generic.TemplateView): template_name = ''manager/add_product.html'' def get(self, request, *args, **kwargs): form = ProductForm(self.request.GET or None, prefix="sch") sub_form = ImageForm(self.request.GET or None, prefix="loc") context = super(AddProductView, self).get_context_data(**kwargs) context[''form''] = form context[''sub_form''] = sub_form return self.render_to_response(context) def post(self, request, *args, **kwargs): form = ProductForm(request.POST, prefix="sch") sub_form = ImageForm(request.POST, prefix="loc") ...

modelo:

{% block container %} <div class="container"> <br/> <form action="{% url ''manager:add_product'' %}" method="post"> {% csrf_token %} {{ form.as_p }} {{ sub_form.as_p }} <p> <button type="submit">Submit</button> </p> </form> </div> {% endblock %}