I'm new to Python and trying to develop simple web application.
In the code below I am trying to retrieve values from DB and rending on HTML page
I'm able to see the HTML page but not values passed. Please help me here.
Python code
#app.route('/userDetails', methods=['POST', 'GET'])
def userDetails():
if request.method == 'POST':
print('in get method')
userid = request.form['userId']
print('user id ', userid)
conn = mysql.connect()
cursor = conn.cursor()
# Get User Details
print('execut sql')
result = cursor.execute("SELECT * FROM tbl_user WHERE user_id= %s", [userid])
if result > 0:
data = cursor.fetchall()
for row in data:
userId = row[0]
name = row[1]
userName = row[2]
password = row[3]
return render_template("userDetails.html", userId=userId, name=name, userName=userName, password=password)
else:
return render_template('index.html')
cursor.close()
HTML code below.
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<title>Python Flask Bucket List App</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h3 class="text-muted">Python Flask App </h3>
</div>
<div class="jumbotron">
<h1>Display User Details</h1>
<div class="jumbotron">
<form class=class="form-userDetails, action="/userDetails", method="POST">
User ID:<input type="text" name="userId" class="form-control">
Name <output name="name" id="name" for="userId" class="form-control"></output>
User Name <output name="userName" id="userName" for="userId" class="form-control"></output>
Password <output name="password" id="password" for="userId" class="form-control"></output>
</br>
<button id="btnretive" class="btn btn-lg btn-primary btn-block" type="submit">Retrive</button>
</form>
</div>
<div class="Footer">
<footer class="footer">
<p>© Company 2015</p>
</footer>
</div>
</div>
</body>
</html>
#DRaj, you are using <output> tag in incorrect way. From the specification,
The HTML Output element () is a container element into which a site or app can inject the results of a calculation or the outcome of a user action.
For more info and example refer to this Mozilla page.
Now,
Flask uses Jinja2 template engine for its HTML rendering. So, the correct way to output values would be to enter a python variable inside Expression delimiters {{ ... }} in the HTML and pass the variables to render_template method.
i.e.
<form class=class="form-userDetails, action="/userDetails", method="POST">
User ID:<input type="text" name="userId" class="form-control">
Name: {{ name }}
User Name: {{ userName }}
Password: {{ password }}
</br>
<button id="btnretive" class="btn btn-lg btn-primary btn-block" type="submit">Retrive</button>
</form>
and the python code should be:-
return render_template("userDetails.html", name=name, userName=userName, password=password)
Refer to this Jinja template designer documentation for more information.
Related
I try to create my own session middleware and my uauth system using Django. I've got the following code:
class CheckSessionsExistMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
...
response = self.get_response(request)
...
response.status_code = 401
response.reason_phrase = 'Unauthorized'
realm = 'some_app'
response['WWW-Authenticate'] = f'Basic real={realm}'
return response
When i set to respone header 'WWW-Authenticate' the string that contains word 'Basic', Django returns "internal" the sign in form and i do not understand.
Link to example of "internal" sign in form that Django returns: https://psv4.userapi.com/c235131/u2000021998/docs/d23/bc9d828c3755/file.png?extra=0qo4COrPeQh3mwjuRs1WoYsB3GVW8WB-Xn01jjtQz7muPVFWRqKjsm0itRqJFhOqjoYoKQGpAqWbG4xNQlJD3_kcs1u0UNct_76s6b1jv0u9oW76cnH2bGBTWWt_hpSQY-OpgxtRj_h56RPnwMZC73NRHw
Is there a way to disable this behavior?
Example of returning html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="login_form" action="http://127.0.0.1:8000/auth/register/" method="post">
<label for="username_input">
Usesrname
</label>
<input type="text" id="username_input" name=""> <br>
<label for="password_input">
Password
</label>
<input type="text" id="password_input" style="margin-left: 10px"> <br>
<input type="submit" value="Sign in">
</form>
Is it first time? Sign up
</body>
</html>
I expected that Django just return to client the header 'WWW-Authenticate' with value 'Basic realm=some_app' and my html form without "internal" sign in form.
I have two input buttons. One is for uploading a file, and the other one is a submit button that adds the uploaded file to the database.
My problem is, after I submit the file, the first button that's used for uploading goes back to "No file chosen" next to the button. However, I want the uploaded file name to "stick" to the UI/html page as the file chosen.
Here is my File class:
class Files(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, unique=True, nullable=False)
data = db.Column(db.LargeBinary)
Here is my HTML code:
<td>
<form class="" action="{{url_for('main.upload_file')}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{row.id}}">
<input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" id="upload" value ="{{row.name}}"> <br>
<input style="margin-bottom: 10px;" type="submit" name="" value="Submit"> <br>
</form>
<a href={{ url_for('main.files') }}>Go to Downloads Page</a>
<br>
</td>
I've tried making the value attribute equal to the file name getting passed in ex. value ="{{row.name}}" for the file type <input> above, but that doesn't keep the file chosen name on the page after submission either. I can't find any videos or posts that deal with this problem, so I would really appreciate any guidance. TIA!
I think setting a default value for an input field of type file is forbidden for security reasons.
However, if you want to keep the name of the selected file, you can aim for a transfer with AJAX. Here you can suppress the standard behavior of the form. The page is not reloaded and the form is not reset.
The example below shows you how it works.
Flask (app.py)
from flask import Flask
from flask import (
render_template,
request,
)
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload-file', methods=['POST'])
def upload_file():
if 'csvfile' in request.files:
file = request.files['csvfile']
if file.filename != '':
# handle file here!
return '', 200
return '', 400
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form name="my-form" method="post">
<input type="file" name="csvfile" />
<input type="submit" />
</form>
<script type="text/javascript">
((uri) => {
const elem = document.querySelector('form[name="my-form"]');
elem.addEventListener('submit', evt => {
evt.preventDefault();
const formData = new FormData(evt.target);
fetch(uri, {
method: 'post',
body: formData
}).then(resp => {
if (resp.status === 200) {
console.log('Submit successful.');
}
});
})
})({{ url_for('.upload_file') | tojson }});
</script>
</body>
</html>
I don't know if it is possible to default the value the file-input field shows but what you could do is just have a row above the input field showing the currently uploaded/chosen file (if there is any). So something like this:
<td>
<form class="" action="{{url_for('main.upload_file')}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{row.id}}">
{% if row.name %}
<p>Currently chosen file: {{row.name}}</p>
<p>You can select a new file below</p>
{% endif %}
<input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" id="upload"> <br>
<input style="margin-bottom: 10px;" type="submit" name="" value="Submit"> <br>
</form>
<a href={{ url_for('main.files') }}>Go to Downloads Page</a>
<br>
</td>
so far this is what I came up with
#html ask user to input information including an image
<div class="form-group">
<input autocomplete="off" autofocus class="form-control" name="name" placeholder="name" type="text">
</div>
<div class="form-group">
<input class="form-control" name="subject" placeholder="subject" type="text">
</div>
<div class="form-group">
<input class="form-control" name="experience" placeholder="experience" type="text">
</div>
<div class="form-group">
<input class="form-control" name="phone" placeholder="puone-number" type="number">
</div>
<div class="form-group">
<input type="file" name="pic" id="pic">
</div>
<button class="btn btn-primary" type="submit">Register</button>
</form>
flask
#app.route("/register", methods=["GET", "POST"])
def register():
"""Show teacher registering menu"""
if request.method == "GET":
return render_template("register.html")
else:
# get the user input
name = request.form.get("name")
sub = request.form.get("subject")
exp = request.form.get("experience")
phone = request.form.get("phone")
f = request.files['pic']
pic = f.save(secure_filename(f.filename))
if not name or not sub or not exp or not phone:
return "404"
# insert in the database
sql = "INSERT INTO teachers (name, sub, exp, phone, pic) VALUES (?, ?, ?, ?, ?)"
db.execute(sql, name, sub, exp, phone, pic)
# inform the user for the success of the process
return render_template("success.html")
showing the results on html
<div>
{% for i in query %}
<div class="media bg-primary text-white">
<img class="align-self-end mr-3" src={{ i['pic'] }} alt="Generic placeholder image">
<div class="media-body">
<h5 class="mt-0">Mr. {{ i['name'] }}</h5>
<ul class="list-group list-group-flush text-dark">
<li class="list-group-item">subject: {{ i['sub'] }},</li>
<li class="list-group-item">experience: {{ i['exp'] }},</li>
<li class="list-group-item">Contact number: {{ i['phone'] }}</li>
</ul>
</div>
</div>
<br>
{% endfor %}
</div>
but right now every time I try it I find the value of the image column in my sql table to be NULL.
How can I fix that
pic = f.save(secure_filename(f.filename))
The save method returns None, so here pic will be None.
I think you intended to write its filename to the database, so perhaps change this to:
pic = secure_filename(f.filename)
f.save(pic)
Now pic is the filename on your server, so you just need to reconstruct this wherever the file is viewed.
Of course be aware that this uses the filename of the file which was uploaded by the user. You may wish to avoid this, incase of duplicates or just for cleanliness. See this other answer I wrote regarding that.
EDIT: Regarding your template.
When it comes to loading the picture in the template, let's assume the filename came through as image.jpg, and you use your exisiting code:
<img src={{ i['pic'] }}>
You could view the source of the rendered page, and see:
<img src=image.jpg>
Two problems with this:
that attribute should have quotes (<img src="image.jpg">)
that's trying to load the file from whichever path is rendered in the browser, so if the URL was http://example.com/subdir/ it's looking for the image at http://example.com/subdir/image.jpg. This can also be verified in the Network tab of your browsers dev tools.
The solution, build the URL with flask's url_for function:
<img src="{{ url_for('static', filename=i['pic']) }}">
This, of course, assumes that you've saved the file to the static directory on your server. You may wish to ensure this in the python code:
import os
# ...
pic = secure_filename(f.filename)
f.save(os.path.join('static', pic))
I have a webpage using the Dimension template, this template uses "popups" instead of new pages when navigating the site. The link is to a demo of this template for illustration. What I would like to do is: client goes to mysite.com/#recipescraper -> 'popup' of submission form -> submit form -> pop up replaced by a "thank you" popup.
So far in Python 3.6 I have the following code:
#app.route('/')
def homepage():
return render_template('index.html')
#--- Cookpad Scraper Stuff ---#
#app.route('/#Scraper', methods=['GET','POST']) #allow get and post requests
def scraper(): # sending via forms as a post request (behind the scenes)
#--- Check if its a post or get request: ---#
if request.method == 'POST': #this block is only entered if the form is submitted
url = request.form.get('recipe')
user = request.form['name']
#--- Assign variables to the multiple choices ---#
category = request.form.get('category')
dessert = request.form.get('dessert')
main_dish = request.form.get('main_dish')
side_dish = request.form.get('side_dish')
soup = request.form.get('soup')
mommy = request.form.get('mommy')
#--- Make sure a valid url was submitted ---#
check_url = 'https://cookpad.com'
if check_url in url: #if a string is submitted with https://cookpad.com in it
title = recipe(url, category, dessert, main_dish, side_dish, soup, mommy, user) #puts the title_ext returned from recipe() into the title variable
send_data(title, url, mommy, category) # send data to rethinkdb: cookpad_scrape database
publish(user) #publishes the scraped recipe into wiki
telegram(user, title) #notifies telegram
return redirect(url_for('thanks', title=title, user=user)) #redirects to url.com/thanks?title=something&user=something_else. Variables are in the link
else: #otherwise return bad_link.html
return redirect(url_for('bad_link', link=url, user=user))
#--- Make the form ---#
return render_template('#Scraper')
This works perfectly, up to the point when the client clicks "submit". For some reason I get a 405 'Method not allowed' error. I did confirm that this code works when the scraper page is on a separate 'mysite.com/scraper' without the popup. I have no experience with CSS/JS, but I'm assuming the #Scraper link gets executed without actually submitting to the python server?
This is the code for the webpage and popup:
<!DOCTYPE HTML>
<!--
Dimension by HTML5 UP
html5up.net | #ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>Website</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="../static/css/main.css" />
<!--[if lte IE 9]><link rel="stylesheet" href="../static/css/ie9.css" /><![endif]-->
<noscript><link rel="stylesheet" href="../static/css/noscript.css" /></noscript>
</head>
<body>
<!-- Wrapper -->
<div id="wrapper">
<!-- Header -->
<header id="header">
<div class="logo">
<span class="image" http://theiveyleague.com/wp-content/uploads/2011/07/6-long-hair-mom-dad-daughter-son-son-baby-1024x731.jpg></span>
</div>
<div class="content">
<div class="inner">
<h1>Hi. This is our website.</h1>
<p>All for one, one for all.</p>
</div>
</div>
<nav>
<ul>
<li>More</li>
<li>Scraper</li>
</ul>
</nav>
</header>
<!-- Main -->
<div id="main">
<!-- More -->
<article id="More">
<h2 class="major">More</h2>
<!-- <span class="image main"><img src="../static/images/pic03.jpg" alt="" /></span> -->
[REDACTED]
</article>
<!-- Scraper -->
<article id="Scraper">
<h1 class="major">Cookpad Scraper</h1>
<form method = "POST">
What is the cookpad recipe url? <input type="text" name="recipe"><br>
What is your name? <input type="text" name="name"><br>
Which category applies? <br>
<input type="radio" id="bread" name="category" value="Bread">
<label for="bread">Bread</label>
<input type="radio" id="fruit" name="category" value="Fruit">
<label for="fruit">Fruit</label>
<input type="radio" id="veggies" name="category" value="Veggie" checked>
<label for="veggies">Veggies</label>
<input type="radio" id="other" name="category" value="Other">
<label for="other">Other</label> <br>
<br>What type of meal is it? <br>
<input type="checkbox" id="dessert" name="dessert">
<label for="dessert">dessert</label>
<input type="checkbox" id="main_dish" name="main_dish" checked>
<label for="main_dish">Main Dish</label>
<input type="checkbox" id="side_dish" name="side_dish">
<label for="side_dish">Side Dish</label>
<input type="checkbox" id="soup" name="soup">
<label for="soup">Soup</label> <br>
<br>Did mom make it? </br>
<input type="radio" id="yes" name="mommy" value="yes" checked>
<label for="yes">Yes</label>
<input type="radio" id="no" name="mommy" value="no">
<label for="no">No</label><br>
<br><input type="submit" value="Submit"><br>
</form>
</article>
<!-- Footer -->
<footer id="footer">
<p class="copyright">© Untitled. Design: HTML5 UP.</p>
</footer>
</div>
<!-- BG -->
<div id="bg"></div>
<!-- Scripts -->
<script src="../static/js/jquery.min.js"></script>
<script src="../static/js/skel.min.js"></script>
<script src="../static/js/util.js"></script>
<script src="../static/js/main.js"></script>
</body>
</html>
Basically I am trying to have a "mysite.com/#article" link get passed to python, so python can get ready to read the form that is being submitted.
Well, it should be a given that after hours of trying to solve the issue I find the solution after posting the question.
The '#' just denotes that the form is opened and submitted in the same page. By simply moving a redirect to app.route('/') the issue is solved: we can now "pop up" the form and submit it for analysis as needed.
New python code:
#app.route('/', methods=['GET','POST'])
def homepage():
#--- Check if its a post or get request: ---#
if request.method == 'POST': #this block is only entered if the form is submitted
scraper()
return render_template('index.html')
#--- Cookpad Scraper Stuff ---#
def scraper(): # sending via forms as a post request (behind the scenes)
#--- Check if its a post or get request: ---#
if request.method == 'POST': #this block is only entered if the form is submitted
url = request.form.get('recipe')
user = request.form['name']
#--- Assign variables to the multiple choices ---#
category = request.form.get('category')
dessert = request.form.get('dessert')
main_dish = request.form.get('main_dish')
side_dish = request.form.get('side_dish')
soup = request.form.get('soup')
mommy = request.form.get('mommy')
#--- Make sure a valid url was submitted ---#
check_url = 'https://cookpad.com'
if check_url in url: #if a string is submitted with https://cookpad.com in it
title = recipe(url, category, dessert, main_dish, side_dish, soup, mommy, user) #puts the title_ext returned from recipe() into the title variable
send_data(title, url, mommy, category) # send data to rethinkdb: cookpad_scrape database
publish(user) #publishes the scraped recipe into wiki
telegram(user, title) #notifies telegram
return redirect(url_for('thanks', title=title, user=user)) #redirects to url.com/thanks?title=something&user=something_else. Variables are in the link
else: #otherwise return bad_link.html
return redirect(url_for('bad_link', link=url, user=user))
#--- Make the form ---#
return render_template('#Scraper') #suspect this is not needed
Html code is unchanged. The solution came to me after this fantastic answer on what the
<form action='#'>
means.
I have a Python script that uses Flask web framework to let users ask a question and depending on some certain questions, the application should ask back some questions to the user on a second webpage. The answers to the questions are evaluated based on the questions and displayed on the initial webpage.
model.py
### Importing Flask ###
from flask import Flask, render_template, request, session, redirect, url_for
### Initializing Flask ###
app = Flask(__name__)
#app.route('/')
def index():
return render_template('init.html')
#app.route('/handle_data', methods = ['POST', 'GET'])
def handle_data():
### User Inputs Question ###
userQuestion = request.form['userQuestion']
def model():
message = "Depends on User"
if message == "Depends on User":
return render_template('user_information.html', userQuestion = userQuestion)
else:
message = "Your answer is ABC."
return message
message = model()
return render_template('init.html', userQuestion = userQuestion, message = message)
#app.route('/user_information', methods = ['POST', 'GET'])
def user_information():
userLevel = request.form['userLevel']
userDOJ = request.form['userDOJ']
userType = request.form['userType']
message = "Answer for Eligibility."
return render_template('init.html', userLevel = userLevel, userDOJ = userDOJ, userType = userType, message = message)
if __name__ == '__main__':
app.run()
These are my two HTML files:
init.html (initial webpage)
<!DOCTYPE html>
<html>
<head>
<title>Human Resources</title>
<!-- for-mobile-apps -->
</head>
<body>
<div class="main">
<div class="w3_agile_main_grid">
<h2>Human Resource Portal</h2>
<br>
<p>Hi</p>
<form action="{{ url_for('handle_data') }}" method="post" class="agile_form">
<input type="text" name="userQuestion" placeholder="Ask your question..." required="">
<input type="submit" value="Submit">
</form>
<p>{{ message }}</p>
</div>
</div>
</body>
</html>
user_information.html (second webpage)
<!DOCTYPE html>
<html>
<head>
<title>Human Resources</title>
</head>
<body>
<div class="main">
<div class="w3_agile_main_grid">
<h2>Human Resource Portal</h2>
<form action="{{ url_for('user_information') }}" method="post" class="agile_form">
<!--<input type="text" name="userName" placeholder="Enter your name." required="">-->
<input type="text" name="userLevel" placeholder="What is your level?" required="">
<input type="text" name="userDOJ" placeholder="What is your date of joining?" required="">
<input type="text" name="userType" placeholder="Are you on sabbatical or specialist?" required="">
<input type="submit" value="Submit">
</form>
</div>
</div>
</body>
</html>
When I execute my script and enters a question, what I get is the HTML code for user_information.html as my answer which is not what I want.
Ouput after I click Submit:
https://ibb.co/cwhRpk
Expected output after I click Submit:
https://ibb.co/c7CFh5
https://ibb.co/dX9T25
I can get the desired output if I remove the model() construct but that will make my code inefficient because in my actual application I have to call model() multiple times with different parameters.
Can anyone please suggest me what approach should I take? I'm totally stuck in this part. Thanks, any help is appreciated!
Your nested model() function does not make any sense at all. It returns the result of render_template, which is a complete response including HTTP headers etc. If you try and insert that into another template, Jinja will be forced to try and convert it to a string, which gives the result you see.
This is not at all the way to compose templates. Jinja supports template inheritance; you should call render_template once only, using a child template that inherits from a common base.