Django form error:local variable 'context' referenced before assignment - django

I'm collecting data from form, processing data(right now I'm not) and displaying the result on the same HTML page from where the user submits the form.
Here is my views.py file:
def index(request):
template = 'predictor/index.html'
if request.method =='POST':
form = EvalForm(request.POST)
if form.is_valid():
text ='thank you for submitting form'
else:
text='something wrong.'
context: {
'text':text,
}
return render(request,template,context)
else:
form = EvalForm()
return render(request,template)
Here is my index.html file
<form method="POST" action="{% url 'predictor' %}">
{% csrf_token %}
//all input fields including submit button here
</form>
<div class="result">
{{ text }}
</div>
All other things like urls are configured properly.
What I'm doing wrong here?

You have typo in your code.
Should be context = {'text':text,} instead of context: {'text':text,}.

Related

Render a form function in multiple django templates

I have written a function where the function captures the details from a form and sends an email after form submission. How can I have this functionality rendered to multiple django templates where i can call the form and do so.
Below is the related function..
def emailView(request):
if request.method == 'GET':
form = myform()
else:
form = myform(request.POST)
if form.is_valid():
subject='form Details'
mobile = form.cleaned_data['mobile']
email = form.cleaned_data['email']
dummy = '\nMobile: '+mobile+'\nEmail: '+email'
try:
send_mail(subject, dummy, 'dummy#gmail.com', ['dummy1#gmail.com', 'dummy2#gmail.com'])
messages.success( request, " Thank you !! For contacting.')
except BadHeaderError:
return HttpResponse('Invalid header found.')
return redirect('email')
return render(request, "my_app/email.html", {'form': form})
You can use include tag to do so. Try out the below way.
consider the below as your url in urls.py
path('your_form/', views.emailView, name='myform'),
you can call your function any number of templates using the below tag.
#template1.html
<form method="post" action="{% url 'myform' %}">
{% include 'yourapp/email.html' %}
<button type="submit">Submit</button>
#template2.html
<form method="post" action="{% url 'myform' %}">
{% include 'yourapp/email.html' %}
<button type="submit">Submit</button>

Context Variable renders the previous value upon refresh

I have created a form that accepts a file upload and fetches some interesting data from the file upon POST.
However, upon refreshing the page, the form is back to its initial state but the data from the previous file remains. How do I fix it?
Here's my code:
forms.py
choices = (('all', 'all'),
('one', 'one'))
class TicketDetailForm(forms.Form):
file = forms.FileField()
type = forms.ChoiceField(choices=choices)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
views.py
def home(request):
detail = []
if request.method == 'POST':
form = TicketDetailForm(request.POST, request.FILES)
if form.is_valid():
if form.cleaned_data['type'] == 'all':
file = form.cleaned_data['file'].read()
detail.append([str(file, 'utf-8')])
# more workaround with the file
else:
form = TicketDetailForm()
return render(request, 'home.html', {'form': form,
'detail': detail})
home.html
{% extends 'base.html' %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{form.as_p}}</p>
<input type="submit" value="Submit"/>
</form>
{% if detail %}
<div class="row">
<p>The detail is as follows:</p>
{% for d in detail %}
{{ d }}
{% endif %}
</div>
{% endif %}
{% endblock %}
This is because you re-post the form when you refresh the page, since your view just renders the template even if the form is valid. The proper behaviour for a server is to always redirect after successfully submitting a POST. In other words, inside if form.is_valid() you should end by return redirect('home').
Your views should always do the following:
For a GET request, render the template
For a POST request and invalid form, render the template (with the invalid form so the user can fix errors). Hitting refresh is ok here, it will just re-submit the invalid form and therefore won't cause issues.
For a POST request and valid form, redirect, so that the last request is a GET request and the user cannot re-submit when refreshing. This also avoids the valid form to be rendered again.

Django - passing data and redirecting between views

I'm making a project related to quizzes online and I'm stuck at the moment where I want to pass data from one view to another. My goal is to get a quiz name from the user in the form in one view and pass it to another view, after submitting a form.
I've made 2 views:
add() - which has the first form with the name for the quiz and redirects to add_questions with the name of the quiz
add_questions() - which captures the name of the submitted quiz and displays another form for the questions
views.py
#login_required
def add(request):
if request.method == 'POST':
QuizForm = QuizNameForm(request.POST)
if QuizForm.is_valid():
# create a quiz
new_quiz = QuizForm.save(commit=False)
new_quiz.owner = request.user
new_quiz.save()
request.session['quiz_id'] = new_quiz.id
print("Quiz saved, now I'm redirecting to add_questions")
return redirect(add_questions)
#return HttpResponseRedirect('add_questions') --- didn't work
#return render(request, 'quiz/add_questions.html', {}) --- didn't work
else:
QuizForm = QuizNameForm()
return render(request, 'quiz/add.html', {'quizForm': QuizForm})
#login_required
def add_questions(request):
print("Add questions here! I've captured a quiz named: {}".format(quiz.name))
quiz = DB_questions.objects.get(id=request.session['quiz_id'])
if request.method == 'POST':
print("ok, post method - cool")
#create a question/answer forms
else:
print("Got into else in add_questions view")
Question_form = QuestionForm()
return render(request, 'quiz/add_questions.html', {'quiz_name': quiz.name, 'question_form': Question_form })
My template for adding quiz name - templates/add.html
<div class="container">
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4">
<!-- Get name of the quiz-->
<form action="{% url 'add' %}" method="post">
{% csrf_token %}
{{ quizForm.name }}
<input class="btn btn-success w-100" type="submit" value="Proceed">
</form>
</div>
<div class="col-md-4"></div>
</div>
</div>
Template to display the name and question form - templates/add_question.html
<div class="row">
<div class="col-md-5"></div>
<h2 class="select_title"> Quiz: {{ quiz_name }}</h2>
<div class="col-md-5"></div>
</div>
<form action="{% url 'add_questions' %}" method="post">
{% csrf_token %}
{{ question_form.content }}
</form>
And finally the urls.py
urlpatterns = [
# ...
url(r'^add', views.add, name='add'),
url(r'^add_questions', views.add_questions, name='add_questions'),
]
The main problem is that after submitting the quiz name the system adds a quiz into database but doesn't redirect me to "add_questions". It still stays in "add" view.
Also I'm not sure if that's the proper way of how I should implement it. I've found many different ways of how I could do it but none of those worked out for me. (Solutions like HttpResponseRedirect(), redirect(), render() etc.)
To sum up:
1) What's the best way, in this case, to transfer data between views after submiting it in the form?
2) How should I redirect to another view so that it would display proper template?
As far as I know, this should work fine for you:
views.py:
#login_required
def add(request):
if request.method == 'POST':
QuizForm = QuizNameForm(request.POST)
if QuizForm.is_valid():
# create a quiz
new_quiz = QuizForm.save(commit=False)
new_quiz.owner = request.user
new_quiz.save()
print("Quiz saved, now I'm redirecting to add_questions")
return render(request, 'quiz/add_questions.html', {'quiz_id': new_quiz.id})
else:
QuizForm = QuizNameForm()
return render(request, 'quiz/add.html', {'quizForm': QuizForm})
#login_required
def add_questions(request):
quiz = DB_questions.objects.get(id=request['quiz_id'])
if request.method == 'POST':
print("ok, post method - cool")
#create a question/answer forms
else:
print("Got into else in add_questions view")
Question_form = QuestionForm()
return render(request, 'quiz/add_questions.html', {'quiz_name': quiz.name, 'question_form': Question_form })
This way you can both render your template and also send the quiz_id through the request object (not session).

django view redirects to URL it shouldn't

I have the following view
def edit_booking(request, pk=None):
if not request.user.is_authenticated:
raise Http404
agent = Agent.objects.get(user=request.user)
booking = get_object_or_404(Booking, pk=pk)
form = BookingForm(request.POST or None, instance=booking)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(instance.get_absolute_url())
elif form.errors:
messages.error(request,"There was a problem, please try again")
context = {
"form": form,
}
return render(request,'booking_form.html', context)
I use the following urls.py
urlpatterns = [
url(r'^booking/create', create_booking, name="create-booking"),
url(r'^booking/$', booking_list, name="booking-list"),
url(r'^booking/(?P<pk>\d+)/$', booking_detail, name="booking-detail"),
url(r'^booking/(?P<pk>\d+)/edit', edit_booking, name="edit-booking"),
]
For some reason when I try to submit the form after editing some booking (e.g. http://127.0.0.1:8000/booking/24/edit) I am automatically redirected to (http://127.0.0.1:8000/booking/24/).
As far as I can tell django is not processing any further code in the view. I tried to figure out with simple print("something") to see where in the code it ends up but it just goes to the url right away as soon as I submit from the template. For completeness sake this is the template:
{% extends 'base.html' %}
<div class="col-sm-6 col-sm-offset 3">
{% block content %}
<form method="POST" action=".">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save"/>
</form>
{% endblock %}
</div>
".", which you used as the action of the form, is interpreted by browsers as "the base of the current path directory". Since you have not used a trailing slash in your /edit URL, the browser submits the form to the nearest base, ie /booking/24.
You should always use a trailing slash:
url(r'^booking/create/$', create_booking, name="create-booking"),
url(r'^booking/$', booking_list, name="booking-list"),
url(r'^booking/(?P<pk>\d+)/$', booking_detail, name="booking-detail"),
url(r'^booking/(?P<pk>\d+)/edit/$', edit_booking, name="edit-booking"),
You need to check for the request method otherwise it will redirect on initial form rendering because django uses the same view for initial rendering and submitting the form.
if request.method == 'POST':
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(instance.get_absolute_url())
elif form.errors:
messages.error(request,"There was a problem, please try again")
else:
context = {
"form": form,
}
return render(request,'booking_form.html', context)

Invalid form when uploading a file

I am trying a basic example in uploading a file with django.
I tried the code from the django documentaion but I keep getting invalid form. And when I don't test the validation of the form and try to handle the file directly, I get:
MultiValueDictKeyError at /neurons/nblast
"
'file'"
P.S:
Previously, I had used a model with a FileField and set the (upload_to), but in my current case I don't need to use the model, I only need to let the user uploads his files.
This is my code:
Template
<body>
<form action="" method="post">
{{ form }}
<br>
<button class="btn btn-success" name="btn_upload">
<span class="glyphicon glyphicon-upload"></span>
<b>Upload</b>
</button>
{% csrf_token %}
</form>
</body>
Views
def test(request):
if request.method == GET:
form = UploadFileForm()
if request.method == POST:
if 'btn_upload' in request.POST:
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
else:
print 'Not Valid'
form = UploadFileForm()
return render_to_response('test.html',
{'form': form},
context_instance=RequestContext(request))
Forms:
class UploadFileForm(forms.Form):
file = forms.FileField()
Thank you very much
Have you tried looking at The Django 'File Uploads' docs , especially the enctype="multipart/form-data" attribute?
u missed this one enctype="multipart/form-data"