I am working on my first django webaite, I am trying to submit two forms one after the other.
Here is the views.py :
def home(request):
import json
if request.method == 'POST':
form = MajorForm(request.POST)
if form.is_valid():
url = 'http://www.mysite.com:8082'
dataout = {'my':'data'}
headers = {'content-type':'application/json'}
r = requests.post(url,data=json.dumps(dataout),headers=headers)
return collector(request)
else:
return HttpResponse("thnx")
else:
form = MajorForm()
return render(request,'index.html',{'form':form})
def collector(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
return HttpResponse("thanx")
else:
return HttpResponse("not valid")
else:
form = ContactForm();
return render(request,'collector.html',{'form':form})
So the first view calls the second view. The first form works fine, and the second form is also displayed fine, but submitting the second form does not work at all ( I was never able to get to form.is_valid path). Maybe this entire approach of calling one view from another is not correct? What would be the right one?
Please indent your code correctly. Also you are missing an else in the collector function when the request.method is not POST.
Related
I am trying to submit a form but receiving an error:
UnboundLocalError at /create/
local variable 'spr' referenced before assignment
Below is the section of my views.py file that is highlighted in the error, specifically:
return HttpResponseRedirect("/%i" %spr.id)
def create(response):
if response.method == "POST":
form = CreateNewSprint(response.POST)
if form.is_valid():
n = form.cleaned_data["name"]
spr = Sprint(name=n)
spr.save()
response.user.sprint.add(spr)
return HttpResponseRedirect("/%i" %spr.id)
else:
form = CreateNewSprint()
return render(response, "main/create.html", {"form": form})
I am unsure of why this is happening, any pointers in the right direction would be greatly appreciated. If any other code/information is needed please let me know.
If the form.is_valid() returns False, then it will aim to evaluate return HttpResponseRedirect("/%i" %spr.id), but spr is never set in that case. You thus should in that case rerender the invalid form:
def create(response):
if response.method == 'POST':
form = CreateNewSprint(response.POST)
if form.is_valid():
n = form.cleaned_data['name']
spr = Sprint(name=n)
spr.save()
response.user.sprint.add(spr)
return HttpResponseRedirect('/%i' %spr.id)
else:
form = CreateNewSprint()
return render(response, 'main/create.html', {'form': form})
Note: You can make use of redirect(…) [Django-doc] and
determine the url based on the view name and the parameters. This is more safe and elegant than performing string formatting and
then wrap it in a HttpResponseRedirect object [Django-doc].
I want to write test for my code and pass a value to a form how can i do that? I have two form in my code and this value should pass just to one of them.
my unittest:
def test_user_has_project(self):
resp = self.client.post('/register/', NEW_USER)
self.assertRedirects(resp, '/register/confirm/')
confirmation_code = self.client.session['confirm_code']
resp = self.client.post('/register/confirm/',
{'confirm_code':confirmation_code})
but this code pass confirmation code to both forms.
my views:
if request.method == 'POST':
form = forms.RegistrationConfirmForm(request.POST)
if (form.is_valid() and
form.cleaned_data['confirm_code'] == request.session['confirm_code']):
# Register the user in the backend
form = forms.RegistrationForm(request.session['registering_user'])
sorry. I'm a beginner in both coding and asking question!
I'm struggling to understand how to submit data from two django forms into two separate database tables from the same view. I only want one submit button. While this question got me closer to the solution, I'm getting errors and the data is not writing to the database. I think this code actually checks the two forms against each other instead of submitting both forms in one go. Any ideas?
Here's what I've tried:
For one form --> one table. This works, so it's a start.
# views.py
def BookFormView(request):
if request.method == 'POST':
form = BookForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect("/books/")
else:
form = BookForm()
return render(request, 'books/createbooks.html',
{'form' : form})
However, when I add this form in from forms.py to get the subsequent views.py I get local variable 'book_form' referenced before assignment. That's usually an easy global-vs-local variable issue to fix, but I don't know what it means in this case.
def BookFormView(request):
if request.method == 'POST':
if 'book' in request.POST:
book_form = BookForm(request.POST, prefix='book')
if book_form.is_valid():
book_form.save()
return HttpResponseRedirect("/books/")
bookdetailsform = BookDetailsForm(prefix='bookdetails')
elif 'bookdetails' in request.POST:
bookdetailsform = BookDetailsForm(request.POST, prefix='bookdetails')
if bookdetailsform.is_valid():
bookdetailsform.save()
return HttpResponseRedirect("/books/")
book_form = BookForm(prefix='book')
else:
book_form = BookForm(prefix='book')
bookdetailsform = BookDetailsForm(prefix='bookdetails')
return render(request, 'books/createbook.html',
{'book_form' : book_form,
'bookdetailsform': bookdetailsform})
Based on the question's comments:
def BookFormView(request):
if request.method == 'POST':
book_form = BookForm(request.POST, prefix='book')
bookdetailsform = BookDetailsForm(request.POST, prefix='bookdetails')
if book_form.is_valid() and bookdetailsform.is_valid():
book_form.save()
bookdetailsform.save()
return HttpResponseRedirect("/books/")
else:
book_form = BookForm(prefix='book')
bookdetailsform = BookDetailsForm(prefix='bookdetails')
return render(request, 'books/createbook.html',
{'book_form': book_form, 'bookdetailsform': bookdetailsform})
I think the problem is that when a user submits a bookdetails post request,
it will be handled under if 'book' in request.POST: condition. Why?
because string bookdetails contains string book, no matter the type of request they do, it will be handled with if book in request.POST: condition.
I believe fixing that if condition problem is the first step.
Can someone explain to me why form 2 executed twice? In another word, I would see 2 print statements, "Hello from form 2," in the console.
The first print statement occurred after I clicked "Submit" from form 1. Second print statement comes after the second "Submit" I clicked from form 2. How do I make it to only print once?
views.py
def form1 (request):
NameFormSet = formset_factory (NameForm, formset = BaseNodeFormSet, extra = 2, max_num = 5)
if request.method == 'POST':
name_formset = NameFormSet (request.POST, prefix = 'nameform')
if name_formset.is_valid ():
data = name_formset.cleaned_data
request.session ['data'] = data
return HttpResponseRedirect ('form2')
else:
name_formset = NameFormSet (prefix = 'nameform')
context = {'name_formset': name_formset}
return render (request, 'nameform/form1.html', context)
def form2 (request):
data = request.session ['data']
print ('Hello from form 2') # <==== This statement printed twice in the console
CheckBoxFormSet = formset_factory (CheckBox, extra = 2, max_num = 5)
if request.method == 'POST':
checkbox_formset = CheckBoxFormSet (request.POST, prefix = 'checkbox')
if checkbox_formset.is_valid ():
for i, form in enumerate (checkbox_formset.cleaned_data):
data [i].update (form) # Join cleaned data with original data
del request.session ['data']
context = {'data': data}
return render (request, 'nameform/success.html', context)
checkbox_formset = CheckBoxFormSet (prefix = 'checkbox')
context = {'checkbox_formset': checkbox_formset, 'data': data}
return render (request, 'nameform/form2', context)
Update 1:
The "print" statement is actually a backend method that processes the data obtained from form 1 and display it in form 2. Leaving where it is now would cause that method to process the information twice. I have no issue or error doing it this way but it's unnecessary.
For example:
def form2 (request):
data = request.session ['data']
n, errors = getInfo (data) # <==== This statement performed twice in the console
if request.method = 'POST':
....
if checkbox_formset.is_valid ():
for i, form in enumerate (checkbox_formset.cleaned_data):
data [i].update (form) # Join cleaned data with original data
n.process_new_data (data, errors)
del request.session ['data']
context = {'data': data, 'errors': error}
return render (request, 'nameform/success.html', context)
else:
checkbox_formset = CheckBoxFormset (prefix = 'checkbox')
context = {'data': data, 'errors': error}
return render (request, 'nameform/form2.html', context)
Update 2:
Since my explanation is a little long, allow me address Ale question here.
Yes, I fully understand why it processed twice. To briefly answer your question, putting getInfo inside 'POST' will give me a context, unbound error because of the context "errors" dictionary doesn't exist in the first redirect.
context = {'data': data, 'errors': errors}
I'd to update my post so that I can explain why I can't use your method. GetInfo takes the data from form1, processes it, and passes it on to form 2 to display. I could do all that in form1 but then I would have to redo it in form2 because form2 will not know what 'n' or 'errors' is without passing it through sessions. I'm just trying to see if there's a better way to do this.
The form2 view is run twice, once as a redirect from form1 which creates the form and renders the template, missing the if request.method == 'POST' part as this time around the request is a 'GET'.
When you submit form2 back to the same view method it prints the line you indicate again, this time the code in the if block executes as the request is a 'POST'.
The key is this line that redirects to the form2 view:
return HttpResponseRedirect ('form2')
You can debug this by including the stacktrace to you print statements:
import traceback
print ''.join(traceback.format_stack())
I have the following view:
def process(request):
if request.method == 'POST':
data = request.POST
results = Specs.objects.filter(screenGroup = data['screen_user'], storage = data['storage_user'], mSystem = data['system_user'] )
context = {'results' : results}
return render(request, 'process.html', context)
When the user inputs the three values it filters correctly, but when it just inputs one or two (or nothing), then it filters passing the value None. Is there any way to ignore the filter if it's not set?
Thanks!
EDIT:
The following code is working, but it's obviously a very unefficient way:
def process(request):
if request.method == 'POST':
data = request.POST
if(data['screen_user'] != None):
results = Specs.objects.filter(screenGroup = data['screen_user'])
elif (data['storage_user'] != None):
results = Specs.objects.filter(storage = data['storage_user'])
else:
results = Specs.objects.all()
#plus all the other options...
context = {'results' : results}
return render(request, 'process.html', context)
You can build the filter beforehand:
def process(request):
if request.method == 'POST':
data = request.POST
spec_filter = {}
for attribute in ['screenGroup', 'storage', 'mSystem']:
if attribute in data and data[attribute]:
spec_filter[attribute] = data[attribute]
results = Specs.objects.filter(**spec_filter)
context = {'results' : results}
return render(request, 'process.html', context)
NB: To use this verbatim you would have to change the names of the variables being passed in the request.POST to match those in the Specs model. I did this just to illustrate, but you can easily use the same principle with your variable names. In that case you'll have to be a bit more verbose.
It's called validating your form.. There are two ways of doing this:
create a django form and use myform.is_valid(). You can read about it in the docs
validate it yourself with a few 'if' statements (either on server side or with javascript before sending the ajax call)