Passing variable through response object in Flask framework - html

I need to pass a variable along with response object while complete signup process and display the success message on the same page. I tried so many ways but I couldn't find any idea how to do that. Please look at this scenario and help me out.
#app.route('/signup', methods=['POST', 'GET'])
def signup():
message = ''
email = ''
password = ''
resp = app.make_response(render_template('signup.html'))
if request.method == 'POST':
import datetime
email = request.form['emailInput']
password = request.form['pswdInput']
if len(password) < 3:
message = Markup("<p style='color:red;'> Password Length Should Be More Than 3 Character </p> ")
return render_template('signup.html', message = message)
expire_date = datetime.datetime.now()
expire_date = expire_date + datetime.timedelta(hours=1)
resp.set_cookie('userEmail', email, expires=expire_date)
resp.set_cookie('userPassword', password, expires=expire_date)
message = Markup("<h1> Registration successfull! </h1>")
resp.headers.set('message', message)
return resp
return render_template('signup.html', message = message)
HTML :
<div class="container">
Home
<form id="signup" method="POST" action="{{url_for('signup')}}">
<div class="header">
<h3>Sign Up</h3>
<p>You want to fill out this form</p>
</div>
<div class="sep"></div>
<div class="">
<input type="email" name="emailInput" placeholder="e-mail" autofocus />
<input type="password" name="pswdInput" placeholder="Password" />
<div class="">
<input name="joinCheck" name="joinCheck" value="1" type="checkbox" /><label class="terms">I accept the terms of use</label>
</div>
<input type="submit" id="submitBtn" value="Submit">SIGN UP FOR INVITE NOW</a>
</div>
<div>
{{message}}
</div>
</form>
</div>

resp = app.make_response(render_template('signup.html'))
This is missing your message keyword. Change it to:
resp = app.make_response(render_template('signup.html', message=message))
You need to move this code down also, because to it, it sees the message variable directly above as the empty string and assigns that to its keyword. I would place it right above your resp.set_cookie() code.
Finally, move this:
message = Markup("<h1> Registration successfull! </h1>")
Above the app.make_response() code you just moved. Your message variable needs to be set before the response code is initialized.
Just a small tip: I would change message = " " to message = None. Otherwise, in the compiled HTML, it just looks like there's an empty div. This won't be too detrimental in this small case, but I'd definitely make it a rule of thumb in future, larger projects. Then, in your HTML:
{% if message %}
<div>
{{message}}
</div>
{% endif %}
Cheers.

Related

Online waiting: django submit form and display result in same page

I have an emergent task to make a web page which allow user to input some data and the backend do some calculation and the result needs to be displayed in the same page just below the input field (like air ticket online price check).
I am new to django and html. below is my first test web page of a simple online calculator to try to figure out how to make such web service.
I found a problem that when clicking the "submit" button, it tends to jump to a new web page or a new web tab. this is not what I want. Once the user input the data and click "submit" button, I want the "result" field on the page directly show the result (i.e. partially update only this field) without refresh/jump to the new page. Also I want the user input data kept in the same page after clicking "submit".
I saw there might be several different ways to do this work, iframe/AJAX. However, I have been searching/trying for answers and solutions for several days and none of the answers really work for this very basic simple question!!
html:
<form method="POST">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div>{{ result }}</div>
<button type="submit">Submit</button>
</form>
view.py
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
print(request.POST)
print(result)
context = {
'result': result
}
return render(request, 'blog/post_list.html', context)
I would suggest taking a look at htmx.org which makes this really simple without having to write any actual JS.
For your example:
(1) You add the htmx JS (which is only about 10k) to your HTML, and use hx-post and hx-target to trigger the ajax calls on your form. With these the form will fire an AJAX request, and the hx-target tells htmx to take the response (which you want to be only the result of your calculation) and put it in the div without refreshing the whole page.
See docs for more details on this.
Note also I gave an id to the div containing the result.
You will need to replace hx-post="{% url 'blog:post_list' %}" with the correct name to your view (which we don't know as you didn't post your urls.py).
<html>
<body>
<form method="POST" hx-post="{% url 'blog:post_list' %}" hx-target="#result">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div id="result">{{ result }}</div>
<button type="submit">Submit</button>
</form>
<script src="https://unpkg.com/htmx.org#1.6.1"></script>
</body>
</html>
(2) In your view then you determine if the request is an AJAX request from htmx by checking the headers, in which case you want to only return the result. There are easier or elegant ways to do this (eg. check django-htmx, but just to keep it simple:
from django.http.response import HttpResponse
from django.shortcuts import render
# Create your views here.
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
if request.headers.get('Hx-Request') == 'true':
# return only the result to be replaced
return HttpResponse(str(result))
else:
return render(request, 'blog/post_list.html', {'result': result})

django: html submit form and display result in smae page without jumping/rereshing into new page

I am new to django and html. below is my first test web page of a simple online calculator.
I found a problem that when clicking the "submit" button, it tends to jump to a new web page or a new web tab. this is not what I want. Once the user input the data and click "submit" button, I want the "result" field on the page directly show the result (i.e. partially update only this field) without refresh/jump to the new page. Also I want the user input data kept in the same page after clicking "submit".
I saw there might be several different ways to do this work, iframe/AJAX. However, I have been searching for answers for 5 days and none of the answers really work for this very basic simple question!!
html:
<form method="POST">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div>{{ result }}</div>
<button type="submit">Submit</button>
</form>
view.py
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
print(request.POST)
print(result)
context = {
'result': result
}
return render(request, 'blog/post_list.html', context)

Keyerror when doing a json post request on sqlalchemy

I am working on a project for class where I have to edit starter Code. I keep getting a KeyError code and I am not sure what the issue is.
line 250, in create_venue_submission
name = request.get_json()['name']
KeyError: 'name'
Code Below from new_venue.html
I added id="name", city, etc.. for all the divs . I'm not sure if that is the correct way to do it but thats the only way i figured to pull all the data from the form.
{% extends 'layouts/main.html' %}
{% block title %}New Venue{% endblock %}
{% block content %}
<div class="form-wrapper">
<form id="venueInfo" method="post" class="form">
<h3 class="form-heading">List a new venue <i class="fa fa-home pull-right"></i></h3>
<div id='name' class="form-group">
<label for="name">Name</label>
{{ form.name(class_ = 'form-control', autofocus = true) }}
</div>
<div class="form-group">
<label>City & State</label>
<div class="form-inline">
<div id='city' class="form-group">
{{ form.city(class_ = 'form-control', placeholder='City', autofocus = true) }}
</div>
<div id='state' class="form-group">
{{ form.state(class_ = 'form-control', placeholder='State', autofocus = true) }}
</div>
</div>
</div>
<div id='address' class="form-group">
<label for="address">Address</label>
{{ form.address(class_ = 'form-control', autofocus = true) }}
</div>
<div id='phone_num' class="form-group">
<label for="phone">Phone</label>
{{ form.phone(class_ = 'form-control', placeholder='xxx-xxx-xxxx', autofocus = true) }}
</div>
<div id="genres" class="form-group">
<label for="genres">Genres</label>
<small>Ctrl+Click to select multiple</small>
{{ form.genres(class_ = 'form-control', autofocus = true) }}
</div>
<div id="fb_link" class="form-group">
<label for="genres">Facebook Link</label>
{{ form.facebook_link(class_ = 'form-control', placeholder='http://', autofocus = true) }}
</div>
<input type="submit" value="Create Venue" class="btn btn-primary btn-lg btn-block">
</form>
<script type="text/javascript">
document.getElementById("venueInfo").onsubmit=function(e){
e.preventDefault();
fetch('/venues/create',{
method:'POST',
body:JSON.stringify({
'name': document.getElementById('name').value,
'city': document.getElementById('city').value,
'state': document.getElementById('state').value,
'address': document.getElementById('address').value,
'phone_num': document.getElementById('phone_num').value,
'genres': document.getElementById('genres').value,
'fb_link': document.getElementById('fb_link').value,
}),
headers: {'Content-type': 'application/json'}
})
.then(function(){
})
}
</script>
</div>
{% endblock %}
Code below is from app.py
#app.route('/venues/create', methods=['GET'])
def create_venue_form():
form = VenueForm()
return render_template('forms/new_venue.html', form=form)
#app.route('/venues/create', methods=['POST'])
def create_venue_submission():
name = request.get_json()['name']
print(name)
flash('Venue ' + request.form['name'] + ' was successfully listed!')
return render_template('pages/home.html')
Looks like you're using Flask-WTF to make those form fields, then using a JS function to grab the values from these with getElementById.
The problem is you don't set an id on the form fields. To get a better visualization of this, have a look at the rendered HTML, rather than the template code itself.
So instead of:
{{ form.name(class_ = 'form-control', autofocus = true) }}
You're looking for someting like:
{{ form.name(id='name', class_ = 'form-control', autofocus = true) }}
Then verify that renders to something like:
<input autofocus class="form-control" id="name" name="name" type="text" value="">
Note this now has an id attribute, which should allow your JS function to grab the value.
You'll need to appy this same concept to the other form fields.
I added id="name", city, etc.. for all the divs . I'm not sure if that is the correct way to do it but thats the only way i figured to pull all the data from the form.
Doing this for the divs is no use... document.getElementById('name').value takes the value of an input field, so that's what you'd have to add the id attribute to, as above.
EDIT regarding comment
In your create_venue_submission route, the request.get_json method receives the values submitted by the javascript Fetch request. On the other hand, request.form contains the values if the form is submitted without Javascript.
With the Javascript method: e.preventDefault() prevents that traditional form submission when the button is clicked, and instead submits the Fetch request, with the header {'Content-type': 'application/json'}.
Either by removing that script tag, or running in a browser with javascript disabled it will fall back to the traditional submission method.
So you should probably do some logic in your flask route to test this condition. You can also use request.is_json boolean for this. Remember to do from flask import jsonify. Something like:
if request.is_json:
# Request came in via javascript based on the header provided.
name = request.get_json()['name']
# Add data to database or something
return jsonify({'message':f'{name} was sucessfully listed.'})
else:
# handle traditional form submission
name = request.form['name']
# Add data to database or something
flash('Venue ' + request.form['name'] + ' was successfully listed!')
return render_template('pages/home.html')
Of course you'll then need to handle the returned JSON in your frontend. So insead of:
.then(function(){
})
Something like:
.then(response => response.json())
.then(data => {
console.log(data);
});
Now with the browser's dev tools Console open you should see something like this when submitted:
Object { message: "Burning Man Festival was sucessfully listed." }
Of course you could then swap that console.log line out with anything to manipulate the dom, and access for example data['message'] to get the success string itself.

Contact Us button/smtplib forward details

I am using pythonanywhere to make a website. I have set up a contact us page, and I am attempting to take whatever a user submits as feedback and then forward the information to myself with smtplib. I asked about this on their forums, but they for some reason just deleted my post.
Here is my HTML code:
<title>Contact us!</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/contact.css') }}">
<div class="container">
<form action="contact">
<label for="report">Reason</label>
<select id="report" name="report">
<option value="Bug">Bug</option>
<option value="Suggestion">Suggestion</option>
<option value="Other">Other</option>
</select>
<label for="Subject">Subject</label>
<textarea id="Subject" name="Subject" placeholder="Write something.." style="height:200px"></textarea>
<input type="submit" value="Submit">
</form>
</div>
And here is the python code:
#app.route("/contact", methods=["GET", "POST"])
def feedback():
if request.method == 'GET':
return render_template("contact.html")
else:
result = "Thanks for the feedback!"
report = request.form['report']
Subject = request.form['Subject']
from email.mime.text import MIMEText
import smtplib
gmail_user = 'email#gmail.com'
gmail_password = 'password'
message = MIMEText(report)
message["Subject"] = Subject
message["From"] = gmail_user
message["To"] = gmail_user
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.ehlo()
server.login(gmail_user, gmail_password)
server.sendmail(gmail_user, gmail_user, message.as_string())
server.close()
return render_template('settlement_return.html',result = result)
EDIT: If I manually set report and subject to some misc text string it sends fine. But trying to get the information that someone submits is not giving any results.
As discussed in the comments above -- it looks like the problem was that you were missing the method="POST" in your form tag. That meant that the form was being submitted with the GET method, so the code in the first branch of the if statement in your view was being executed, which meant that no email was being sent.

Email sending in django code is not working

Email sending in django code is not working,
it display error "[Errno 10061] No connection could be made because the target machine actively refused it"
these are my VIEWS.PY
def send_email(request):
username = request.POST.get('username', '')
from_email = request.POST.get('from_email', '')
message = request.POST.get('message', '')
if username and message and from_email:
try:
send_mail(username, from_email, message, ['canonizadocharm#ymail.com'])
except BadHeaderError:
return HttpResponse('Invalid header found.')
return HttpResponseRedirect('/contact/thanks/')
else:
# In reality we'd use a form class
# to get proper validation errors.
return HttpResponse('Make sure all fields are entered and valid.')
these are my contact.html
<FORM METHOD="POST" ACTION="/send_email/" >
{% csrf_token %}
Name: <INPUT TYPE="text" NAME="username"><BR>
Email: <INPUT TYPE="text" NAME="from_email"><BR>
Message: <BR>
<TEXTAREA NAME="message" ROWS="10" WRAP="hard">
</TEXTAREA>
<INPUT NAME="redirect" TYPE="hidden">
<INPUT NAME="NEXT_URL" TYPE="hidden">
<BR>
<INPUT TYPE="submit" VALUE="Send">
<INPUT TYPE="reset" VALUE="Clear">
</FORM>
these are my URLS.PY
url(r'^send_email/', views.send_email),
url(r'^contact/', views.contact),
url(r'^thanks/', views.thanks),
and my SETTINGS.PY
EMAIL_HOST = 'localhost'
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_PORT = 25
EMAIL_USE_TLS = True
Your action value of form must direct to view's url, mailto:canonizadocharm#ymail.com is not a valid path on your server.
UPDATED:
For example, add a new rule to urls.py like,
url(r'^mail/', views.send_mail),
Then change action value to mail.
Have your action value point to a URL, which in turn points to one of your views. For instance, your urls.py can do this.
url(r'^email/', 'project.views.send_email')
This will route your contact form to your send_mail view.
Your form in the templates has no csrf that's why you get an error of "CSRF verification failed".
<FORM METHOD=POST ACTION="/send_email/" ENCTYPE="text/plain">{% csrf_token %}
...........
</FORM>
If you want to know what is csrf just go to this link:
https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
Create email setting in your settings.py, like this for example:
settings.py
# Sending mail
EMAIL_USE_TLS = True
EMAIL_HOST='smtp.gmail.com'
EMAIL_PORT=587
EMAIL_HOST_USER='your gmail account'
EMAIL_HOST_PASSWORD='your gmail password'
views.py
from django.core.mail import send_mail
def send_email(request):
if request.method == 'POST':
username = request.POST.get('username')
message = request.POST.get('message')
from_email = request.POST.get('from_email')
send_mail(username, message, from_email, ['canonizadocharm#ymail.com',])
return HttpResponseRedirect('/contact/thanks/')
else:
return HttpResponse('Make sure all fields are entered and valid.')