how to get different UI elements by the choicefield value? - django

Here's my code, something is wrong in the test.html if statement. Could you help me to modified the if condition in test.html that I can get different UI element by the choice-field value?
forms.py
class testForm(forms.Form):
runtype = forms.ChoiceField(choices=[(0, 0), (1, 1)])
byname = forms.CharField()
byindex = forms.IntegerField()
views.py
#csrf_exempt
def osys(request):
if request.method == 'POST':
form = testForm(request.POST, request.FILES)
if form.is_valid():
runtype = form.cleaned_data['runtype']
if runtype == 0:
byname = form.cleaned_data['byname']
if runtype == 1:
byindex = form.cleaned_data['byindex']
print byname, byindex, runtype, filename
return HttpResponse('OK')
else:
form = testForm()
return render_to_response('test.html', locals())
test.html
<form method="post" >
{{form.runtype}}
{% if form.runtype ==0 %}
{{form.byname}}
{% if form.runtype ==1 %}
{{form.byindex}}
<input type="submit" value="Start Run" name="btnRun"></input>
</form>

Django templates are rendered server side to plain HTML which is sent to the client which has no knowledge of the template code.
If you need to do things dynamically client side, you'll need to use JavaScript.

Related

File uploaded in my form is not showing up in my edit/update form

When I fill out my form with its file, it apparently submits, but when checking it out when editing/uploading, all data in the form shows up except my file. So, I cannot access it at all. I guess it probably has something to do with my views.py (the function is for both, save a form for the first time and visualizing them), so here it goes
#views.py
def contract_form(request, id=0):
if request.method == "GET":
if id == 0:
form = ContractsForm(request.FILES)
else:
contratos = Contratos.objects.get(pk=id)
form = ContractsForm( instance=contratos)
return render(request,"contracts_form.html", {'form':form})
else:
if id == 0:
form = ContractsForm(request.POST, request.FILES)
else:
contratos = Contratos.objects.get(pk=id)
form = ContractsForm(request.POST, request.FILES, instance= contratos, )
if form.is_valid():
form.save()
messages.success(request, "Form submission successful")
else:
messages.error(request, "Error, contract not submitted")
return redirect('/contracts')
Just in case, every other instance that has something to do with the upload file:
#models.py
attached_file=models.FileField(upload_to="media", blank=True)
My form is stated with <form enctype="multipart/form-data" action="" method="post" autocomplete="off" class="row g-3">
#contracts_form.html
<label for="{{ form.subject.id_for_label }}">Attached File:</label>
{{form.attached_file}}
{% if Contracts.media %}
{% endif %}
#settings.py
MEDIA_ROOT=os.path.join(BASE_DIR, 'uploads/')
MEDIA_URL="/contracts-media/"
path('contracts/edit/<int:id>', views.contract_form, name='edit'), #edit/update form
path('contracts/add', views.contract_form, name = 'new-contract'), #add a contract
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
````
There's no text in your link tag
Try
Wonderful Linkiness

The view ___ didn't return an HttpResponse object. It returned None instead

I have a scheduling app where patients can register for appointments. When I submit the form for a new appointment, I get the value error.
views.py
def patient_portal(request):
appointments = Appointment.objects.filter(patient=request.user.patient.pid)
data_input = request.GET.get('date')
selected_date = Appointment.objects.filter(date = data_input).values_list('timeslot', flat=True)
available_appointments = [(value, time) for value, time in Appointment.TIMESLOT_LIST if value not in selected_date]
doctor = Patient.objects.get(doctor=request.user.patient.doctor).doctor
print(doctor)
if request.method == 'POST':
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
if form.is_valid():
form.save()
return redirect('../home/')
else:
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
return render(request, 'scheduling/patient.html', {"form" : form, "appointments" : appointments, "available_appointments" : available_appointments, "data_input": data_input, "doctor": doctor})
patient.html:
<form method="post" action="" id="timeslot" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
forms.py:
class AppointmentForm(forms.ModelForm):
class Meta:
model = Appointment
fields = ('doctor','patient','date','timeslot')
Your view must always return an HTTP response. At the moment, your code doesn't handle the case when request.method == 'POST', but the form is invalid.
You can fix your code by de-indenting the final return statement, to move it outside of the else block:
def patient_portal(request):
...
if request.method == 'POST':
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
if form.is_valid():
form.save()
return redirect('../home/')
else:
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
return render(request, 'scheduling/patient.html', {"form" : form, "appointments" : appointments, "available_appointments" : available_appointments, "data_input": data_input, "doctor": doctor})

Django: Passing value from template to view

I HAD this situation:
Clicking on a html submit button, I call views.stream_response which "activates" views.stream_response_generator which "activates" stream.py and return a StreamingHttpResponse and I see a progressive number every second up to m at /stream_response/:
1
2
3
4
5
6
7
8 //e.g. my default max value for m
stream.py
from django.template import Context, Template
import time
def streamx(m):
lista = []
x=0
while len(lista) < m:
x = x + 1
time.sleep(1)
lista.append(x)
yield "<div>%s</div>\n" % x #prints on browser
print(lista) #print on eclipse
return (x)
views.py
def stream_response(request): // unified the three functions as suggested
if request.method == 'POST':
form = InputNumeroForm(request.POST)
if form.is_valid():
m = request.POST.get('numb', 8)
resp = StreamingHttpResponse(stream.streamx(m))
return resp
forms.py
from django.db import models
from django import forms
from django.forms import ModelForm
class InputNumero(models.Model):
m = models.IntegerField()
class InputNumeroForm(forms.Form):
class Meta:
models = InputNumero
fields = ('m',)
urls.py
...
url(r'^homepage/provadata/$', views.provadata),
url(r'^stream_response/$', views.stream_response, name='stream_response'),
...
homepage/provadata.html
<form id="streamform" action="{% url 'stream_response' %}" method="POST">
{% csrf_token %}
{{form}}
<input id="numb" type="number" />
<input type="submit" value="to view" id="streambutton" />
</form>
If I delete "8" and use only m = request.POST.get('numb') I obtain:
ValueError at /stream_response/ The view homepage.views.stream_response didn't return an HttpResponse object.
It returned None instead.
So, if I try to submit, it takes only the default value 8 (and works) but it not takes my form input. What is it wrong?
-->UPDATE: with #Tanguy Serrat suggestions:
views.py
def stream_response(request):
form = InputNumeroForm()
if request.method == 'POST':
form = InputNumeroForm(data=request.POST)
if form.is_valid():
#Accessing the data in cleaned_data
m = form.cleaned_data['numero']
print("My form html: %s" % form)
print ("My Number: %s" % m) #watch your command line
print("m = ", m)
resp = StreamingHttpResponse(stream.streamx(m))
return resp
#If not post provide the form here in the template :
return render(request, 'homepage/provadata.html', {'form': form,})
forms.py
class InputNumeroForm(forms.Form):
numero = models.IntegerField()
homepage/provadata.py
<form action="/stream_response/" method="POST">
{% csrf_token %}
{{form}} <!--issue: does not appear on the html !!!!!-->
<input type="number" name="numero" /> <!--so I write this-->
<input type="submit" value="to view" />
</form>
If I give as input e.g. 7 from keyboard:
KeyError at /stream_response/
'numero'
WHILE
If I write m = request.POST.get('numero'), in command line I have:
...
My form html:
My Number: 7
m = 7
...
while len(lista) < m:
TypeError: unorderable types: int() < str()
EDIT : ModelForm part removed, no need to save the data in DB so using classic form this way :
Method 1 : Classic Form without Model using Django
in your forms.py
from django import forms
class InputNumeroForm(forms.Form):
numero = forms.IntegerField()
in your views.py
from django.shortcuts import render
def stream_response(request):
form = InputNumeroForm()
if request.method == 'POST':
form = InputNumeroForm(data=request.POST)
if form.is_valid():
#Accessing the data in cleaned_data
m = form.cleaned_data['numero']
print "My Number %s" % m #watch your command line
resp = StreamingHttpResponse(stream.streamx(m))
return resp
#If not post provide the form here in the template :
return render(request, 'homepage/provadata.html', {
'form': form,
})
in your template :
<form id="streamform" action="{% url 'stream_response' %}" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="to view" id="streambutton" />
</form>
To clarify a little there are two types of form in Django :
Classic Forms which do not require saving in a database
Model Forms which will allow you to create forms which are based on a Database Model i.e. (you can add a row to your db or edit one)
Here you don't need to save your number in your database so you use classical forms:
https://docs.djangoproject.com/en/1.8/topics/forms/
Method 2 : Not using the Django Form
For very simple forms like your case :
in views.py
from django.shortcuts import render
def stream_response(request):
if request.method == 'POST':
if request.POST.get('numero', False):
m = int(request.POST['numero'])
print "My Number %s" % m #watch your command line
resp = StreamingHttpResponse(stream.streamx(m))
return resp
return render(request, 'homepage/provadata.html')
in your template :
<form id="streamform" action="{% url 'stream_response' %}" method="POST">
{% csrf_token %}
<input type="number" name="numero" />
<input type="submit" value="to view" id="streambutton" />
</form>
I see a handful of issues with the code you posted:
Your form field is missing the 'name' attribute, and thus the value set for this field will not be passed to your code. This is why your request.POST.get('numb') returns None unless you provide your default (8).
Try this:
<input id="numb" name="numb" type="number" />
Also, I noticed in your form you use models.IntegerField - why are you trying to use a model field here?
A better approach for you may be to add the numb field to your form and then retrieve the value from the form's cleaned data: form.cleaned_data['numb'] instead of the POST data.
Hopefully this gets you going.
Django views MUST return a HttpResponse object. Considering that the other two functions you're referencing have only one line each, it would serve you better to just put everything in one function, or at least move the StreamingHttpResponse to the main function.
Edit: The StreamingResponseHttp must be given an iterable so, going back to the stream.py, try taking out the return and print functions (I've taken out excess stuff for experimentation's sake). This worked for me in the shell.
def streamx(m):
lista = []
x=0
while len(lista) < m:
x = x + 1
time.sleep(1)
lista.append(x)
yield "<div>%s</div>\n" % x #prints on browser
#c = Context({'x': x})
#yield Template('{{ x }} <br />\n').render(c)
def stream_response(request):
if request.method == 'POST':
form = InputNumeroForm(request.POST)
if form.is_valid():
m = request['numb']
resp = StreamingHttpResponse(streamx(m))
return resp

Django 1.6 "CSRF verification failed. Request aborted."

This question may seem like a duplicate but none of the solutions on Google/SO are working, so please do not mark as duplicate.
Here is my view code:
#csrf_protect
def login(request):
if request.POST:
render_to_response('list.tpl', context_instance=RequestContext(request))
else:
# Prepare templates
header = get_template("header.tpl")
body = get_template("login.tpl")
footer = get_template("footer.tpl")
html = header.render(Context({"title": "Login", "charset": "UTF-8"}))
html = html + body.render(Context({}))
html = html + footer.render(Context({}))
return HttpResponse(html)
Here is the login template:
<body>
<div class="bodydiv">
<h3>Login</hd>
<form id="login" method="post" action=".">{% csrf_token %}
User: <input type="text" name="user"><br>
Password: <input type="password" name="password">
<input type="submit" name="submit_login" value="Login">
</form>
</div>
</body>
When I submit the POST request from the form I get CSRF cookie not set.:
I've implemented the four bullets and received the same exact error. What am I missing?
Updated view:
#csrf_protect
def login(request):
print("Method: " + request.method)
if request.method == "POST":
print("IN POST!")
return render(request, 'list.tpl', {})
elif request.method == "GET":
print("IN GET!")
# Prepare templates
header = get_template("header.tpl")
body = get_template("login.tpl")
footer = get_template("footer.tpl")
html = header.render(Context({"title": "Login", "charset": "UTF-8"}))
html = html + body.render(Context({}))
html = html + footer.render(Context({}))
return HttpResponse(html)
You are missing the return. The view is a function and expects you to return an HTTPResponse object.
render_to_response('list.tpl', context_instance=RequestContext(request))
should be
return render_to_response('list.tpl', context_instance=RequestContext(request))
Another thing,
if request.POST
should be
if request.method == 'POST'
Moreover, Avoid using render_to_response. Instead, use render. Source
return render(request, 'list.tpl')
I fixed this issue by using RequestContext instead of Context:
def login(request):
if request.method == "POST":
return render(request, 'login.tpl')
elif request.method == "GET":
# Prepare templates
header = get_template("header.tpl")
body = get_template("login.tpl")
footer = get_template("footer.tpl")
html = header.render(RequestContext(request, {"title": "Login", "charset": "UTF-8"}))
html = html + body.render(RequestContext(request, {}))
html = html + footer.render(Context({}))
return HttpResponse(html)

Proper way to handle multiple forms on one page in Django

I have a template page expecting two forms. If I just use one form, things are fine as in this typical example:
if request.method == 'POST':
form = AuthorForm(request.POST,)
if form.is_valid():
form.save()
# do something.
else:
form = AuthorForm()
If I want to work with multiple forms however, how do I let the view know that I'm submitting only one of the forms and not the other (i.e. it's still request.POST but I only want to process the form for which the submit happened)?
This is the solution based on the answer where expectedphrase and bannedphrase are the names of the submit buttons for the different forms and expectedphraseform and bannedphraseform are the forms.
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')
You have a few options:
Put different URLs in the action for the two forms. Then you'll have two different view functions to deal with the two different forms.
Read the submit button values from the POST data. You can tell which submit button was clicked: How can I build multiple submit buttons django form?
A method for future reference is something like this. bannedphraseform is the first form and expectedphraseform is the second. If the first one is hit, the second one is skipped (which is a reasonable assumption in this case):
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')
I needed multiple forms that are independently validated on the same page. The key concepts I was missing were 1) using the form prefix for the submit button name and 2) an unbounded form does not trigger validation. If it helps anyone else, here is my simplified example of two forms AForm and BForm using TemplateView based on the answers by #adam-nelson and #daniel-sokolowski and comment by #zeraien (https://stackoverflow.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>
Wanted to share my solution where Django Forms are not being used.
I have multiple form elements on a single page and I want to use a single view to manage all the POST requests from all the forms.
What I've done is I have introduced an invisible input tag so that I can pass a parameter to the views to check which form has been submitted.
<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
Django's class based views provide a generic FormView but for all intents and purposes it is designed to only handle one form.
One way to handle multiple forms with same target action url using Django's generic views is to extend the 'TemplateView' as shown below; I use this approach often enough that I have made it into an Eclipse IDE template.
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)
The html template is to the following effect:
...
<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>
...
This is a bit late, but this is the best solution I found. You make a look-up dictionary for the form name and its class, you also have to add an attribute to identify the form, and in your views you have to add it as a hidden field, with the 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)
I hope this will help in the future.
view:
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")
...
template:
{% 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 %}
Based on this answer by #ybendana:
Again, we use is_bound to check if the form is capable of validation. See this section of the documentation:
Bound and unbound forms
A Form instance is either bound to a set of data, or unbound.
If it’s bound to a set of data, it’s capable of validating that data and rendering the form as HTML with the data displayed in the HTML.
If it’s unbound, it cannot do validation (because there’s no data to validate!), but it can still render the blank form as HTML.
We use a list of tuples for form objects and their details allowing for more extensibility and less repetition.
However, instead of overriding get(), we override get_context_data() to make inserting a new, blank instance of the form (with prefix) into the response the default action for any request. In the context of a POST request, we override the post() method to:
Use the prefix to check if each form has been submitted
Validate the forms that have been submitted
Process the valid forms using the cleaned_data
Return any invalid forms to the response by overwriting the context data
# views.py
class MultipleForms(TemplateResponseMixin, ContextMixin, View):
form_list = [ # (context_key, formcls, prefix)
("form_a", FormA, "prefix_a"),
("form_b", FormB, "prefix_b"),
("form_c", FormC, "prefix_c"),
...
("form_x", FormX, "prefix_x"),
]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Add blank forms to context with prefixes
for context_key, formcls, prefix in self.form_list:
context[context_key] = formcls(prefix=prefix)
return context
def post(self, request, *args, **kwargs):
# Get object and context
self.object = self.get_object()
context = self.get_context_data(object=self.object)
# Process forms
for context_key, formcls, prefix in self.form_list:
if prefix in request.POST:
# Get the form object with prefix and pass it the POST data to \
# validate and clean etc.
form = formcls(request.POST, prefix=prefix)
if form.is_bound:
# If the form is bound (i.e. it is capable of validation) \
# check the validation
if form.is_valid():
# call the form's save() method or do whatever you \
# want with form.cleaned_data
form.save()
else:
# overwrite context data for this form so that it is \
# returned to the page with validation errors
context[context_key] = form
# Pass context back to render_to_response() including any invalid forms
return self.render_to_response(context)
This method allows repeated form entries on the same page, something I found did not work with #ybendana's answer.
I believe it wouldn't be masses more work to fold this method into a Mixin class, taking the form_list object as an attribute and hooking get_context_data() and post() as above.
Edit: This already exists. See this repository.
NB:
This method required TemplateResponseMixin for render_to_response() and ContextMixin for get_context_data() to work. Either use these Mixins or a CBV that descends from them.
If you are using approach with class-based views and different 'action' attrs i mean
Put different URLs in the action for the two forms. Then you'll have two different view functions to deal with the two different forms.
You can easily handle errors from different forms using overloaded get_context_data method, e.x:
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
template:
<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>
Here is simple way to handle the above.
In Html Template we put Post
<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>
In View
def addnewroute(request):
if request.method == "POST":
# do something
def addarea(request):
if request.method == "POST":
# do something
In URL
Give needed info like
urlpatterns = patterns('',
url(r'^addnewroute/$', views.addnewroute, name='addnewroute'),
url(r'^addarea/', include('usermodules.urls')),
if request.method == 'POST':
expectedphraseform = ExpectedphraseForm(request.POST)
bannedphraseform = BannedphraseForm(request.POST)
if expectedphraseform.is_valid():
expectedphraseform.save()
return HttpResponse("Success")
if bannedphraseform.is_valid():
bannedphraseform.save()
return HttpResponse("Success")
else:
bannedphraseform = BannedphraseForm()
expectedphraseform = ExpectedphraseForm()
return render(request, 'some.html',{'bannedphraseform':bannedphraseform, 'expectedphraseform':expectedphraseform})
This worked for me accurately as I wanted. This Approach has a single problem that it validates both the form's errors. But works Totally fine.
I discovered a pretty interesting way to send TWO Forms from a single page using the same view. I tried many options but just wanted something that can just work. So here is something that I discovered. But it only works when there are just TWO Forms on a page.
I am using just try and except method to first try first form and if that doesnt works than try second form. This is quiet interesting to know that it works absolutely fine. Don't use it on scalable application as it can create troublesome or may risk the security of the application, else use Class based view to submit mutiple forms or create seperate views for each form.
def create_profile(request):
if request.method=='POST':
try:
biograph = Biography(name=name, email=email, full_name=full_name, slug_name=slug_name, short_bio=short_bio)
biograph.save()
except:
social = SocialMedia(twitter=twitter, instagram=instagram, facebook=facebook, linkedin=linkedin, github=github)
social.save()