Flask: redirecting nonexistent URL's - python

I was given instructions to do the following: modify an app.py file so that my website responds to all possible URLs (aka nonexistent extension like '/jobs', meaning that if an invalid URL is entered, it is redirect to the home index.html page. Here is a copy of my app.py as it stands, any ideas on how to do this?
from flask import Flask, render_template #NEW IMPORT!!
app = Flask(__name__) #This is creating a new Flask object
#decorator that links...
#app.route('/') #This is the main URL
def index():
return render_template("index.html", title="Welcome",name="home")
#app.route('/photo')
def photo():
return render_template("photo.html", title="Home", name="photo-home")
#app.route('/about')
def photoAbout():
return render_template("photo/about.html", title="About", name="about")
#app.route('/contact')
def photoContact():
return render_template("photo/contact.html", title="Contact", name="contact")
#app.route('/resume')
def photoResume():
return render_template("photo/resume.html", title="Resume", name="resume")
if __name__ == '__main__':
app.run(debug=True) #debug=True is optional

I think that what you are looking for is probably just error handling. The Flask documentation has a section that shows how to do error handling.
But to summarize the important points from there:
from flask import render_template
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
You have an app instance, so you can just add this to your code. It's pretty clear that anytime there is a 404 or page does not exist, 404.html will be rendered.
Assuming you are working with jinja templates 404.htmls contents could be:
{% extends "layout.html" %}
{% block title %}Page Not Found{% endblock %}
{% block body %}
<h1>Page Not Found</h1>
<p>What you were looking for is just not there.
<p>go somewhere nice
{% endblock %}
This requires a base template (here layout.html). Say for now you don't want to work with jinja templating, just use this as a 404.html:
<h1>Page Not Found</h1>
<p>What you were looking for is just not there.
<p>go somewhere nice
In your case because you want to see the home page (index.html probably):
#app.errorhandler(404)
def page_not_found(e):
return render_template('index.html'), 404

Related

I am learning Flask and I am facing this issue

I am learning Flask. I wrote the basic code and I want the submitted text to display in the same page. I already wrote the html and connected it. How can I do this?
from flask import Flask, redirect, url_for,render_template, request
app = Flask(name)
#app.route("/", methods=["POST", "GET"])
def home():
if request.method == "POST":
user = request.form["nm"]
return redirect(url_for("/", user))
else:
return render_template("login.html")
if name == ("main"):
app.run(debug=True)
I've noticed that you've taken the code from Python Basics. Indeed they do not show how to format the HTML template of the redirect.
Luckily, they offer a tutorial that shows you how to feed retrieved data to an HTML template using Jinja2. This tutorial can be found here. In essence, you can use {{ variable }} in your HTML template. In Flask, you will have to specify the variable as argument in the render_template function.
Minimal example:
# app.py
#app.route('/result',methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
variable = request.form['variable']
return render_template("result.html", variable=variable)
<!-- result.html -->
<p> This is your variable: {{ variable }} </p>
I advice you to also check out both the Flask and Jinja2 documentation, as they offer plenty comprehensive examples of how to work with callbacks and HTML templating.

How to get test input from an html form to another python script using flask?

I'm trying to get a simple web form up and running that only asks for a URL.
This is the HTML Code (index.html)
<!DOCTYPE html>
<html>
<body>
<form name = 'test' action = "." method = "post">
<form action="test.php" method="get">
URL <input type="text" link="link" name = "URL"/>
<input type="submit" />
</form>
</body>
</html>
I'm using Flask to run the simple web application this is the Flask Code: (app.py)
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/")
def index():
return render_template('index.html')
#app.route("/", methods = ["POST"])
def get_value():
url = request.form["URL"]
return 'The url is ' + url
if __name__ == "__main__":
app.run(debug=True)
and I'm trying to get the inputted URL to another python script so I can do something with it, this is the other python script: (url.py)
from app import get_value
print(get_value())
However, whenever I run python3 url.py it gives me this error:
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
Any idea how to print get the URL over successfully? In a lot of detail preferably because I am very new to Flask.
The error occurs because you called a function that needs data from a request to get the user inputs. You should call the url handling function instead letting the handling function call the retrieval of the url.
Consider this answer https://stackoverflow.com/a/11566296/5368402 to make sure you pass the url correctly. Now that you have your url, simply pass it to your other script.
import url # your url.py module
#app.route("/", methods = ["POST"])
def get_value():
input_url = request.form["URL"]
url.handle_url(input_url) #call a function inside url.py

Flask : ValueError: not enough values to unpack (expected 2, got 1)

I am a Newbee in Python, Flask and API, and trying to learn it with my own project.
The API I am querying requires Basic Authentication.
Created a login.html and dashboard.html as templates of Flask.
Created a module myclasses.py
and the reporter.py which is the main module for Flask Views and other code.
login.html request user for IP, Username and Password which is captured in (/) view, and then forwarded to the Function defined in MyClasses.py using "call_api" to form the API and the function returns the Data.
Now I don't know and not sure how to proceed with forwarding the received data as json to (/dashboard) view for parsing and displaying in Dashboard template page.
from flask import Flask, render_template, url_for, redirect, request, json
from MyClasses import call_api
app = Flask(__name__)
data = "no data"
status_code = 0
#app.route('/dashboard')
def dashboard():
return render_template('dashboard.html', data=data, status_code=status_code)
#app.route('/', methods=["GET", "POST"])
def login():
if request.method == "POST":
creds = {'ipaddr': request.form['inip'],
'username': request.form['inusername'],
'password': request.form['inpassword'],
'entity': 'info'
}
request_dump = call_api(creds['ipaddr'], creds['username'], creds['password'], creds['entity'])
if request_dump[1] == 200:
global data
global status_code
data = (json.dumps(request_dump[0], indent=2))
status_code = request_dump[1]
return redirect(url_for('dashboard')), status_code, data
else:
return render_template('login.html')
else:
return render_template('login.html')
I am getting error, what does this means?
ValueError: not enough values to unpack (expected 2, got 1)
If I remove status_code, data, it works fine.
return redirect(url_for('dashboard')), status_code, data
for sure, I am not doing it the right way in many areas of this code.
Also, If you guys tell me on how to debug the code when flask is involved, I tried using breakpoints in PyCharm but code does not stops when I browse the templates.
Appreciate you help and Thank you for the time.
reconstructing the dictionary to a customized (data that I need) within the dashboard() as well as correcting the Flask template with {% for loop %} resolved the issue.
Flask Template snippet below:
<table class="containertbl">
<tbody>
{% for key,value in ddo.items() %}
<tr>
<th scope="row">{{ key }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</tbody>
</table>

pythonanywhere + flask: website just says 'unhandled exception'. How to get debugger to print stack trace?

Be forewarned of a triple-newbie threat - new to python, new to python anywhere, new to flask.
[pythonanywhere-root]/mysite/test01.py
# A very simple Flask Hello World app for you to get started with...
from flask import Flask
from flask import render_template # for templating
#from flask import request # for handling requests eg form post, etc
app = Flask(__name__)
app.debug = True #bshark: turn on debugging, hopefully?
#app.route('/')
#def hello_world():
# return 'Hello from Flask! wheee!!'
def buildOrg():
orgname = 'ACME Inc'
return render_template('index.html', orgname)
And then in [pythonanywhere-root]/templates/index.html
<!doctype html>
<head><title>Test01 App</title></head>
<body>
{% if orgname %}
<h1>Welcome to {{ orgname }} Projects!</h1>
{% else %}
<p>Aw, the orgname wasn't passed in successfully :-(</p>
{% endif %}
</body>
</html>
When I hit up the site, I get 'Unhandled Exception' :-(
How do I get the debugger to at least spit out where I should start looking for the problem?
The problem is render_template only expects one positional argument, and rest of the arguments are passed as keyword only arguments.So, you need to change your code to:
def buildOrg():
orgname = 'ACME Inc'
return render_template('index.html', name=orgname)
For the first part, you can find the error logs under the Web tab on pythonanywhere.com.
You need to also pass your name of orgname variable that is used in your template to render_template.
flask.render_template:
flask.render_template(template_name_or_list, **context)
Renders a template from the template folder with the given context.
Parameters:
template_name_or_list – the name of the template to be rendered,
or an iterable with template names the first one existing will be rendered
context – the variables that should be available in the context of the template.
So, change this line:
return render_template('index.html', orgname)
To:
return render_template('index.html', orgname=orgname)

Implementing breadcrumbs in Python using Flask?

I want breadcrumbs for navigating my Flask app. An option could be to use a general Python module like bread.py:
The bread object accepts a url string and grants access to the url
crumbs (parts) or url links (list of hrefs to each crumb) .
bread.py generates the breadcrumb from the url path, but I want the elements of the breadcrumb to be the title and link of the previously visited pages.
In Flask, maybe this can be done using a decorator or by extending the #route decorator.
Is there a way to have each call of a route() add the title and link of the page (defined in the function/class decorated with #route) to the breadcrumb? Are there other ways to do it? Any examples of breadcrumbs implemented for Flask?
So you're after "path/history" breadcrumbs, rather than "location" breadcrumbs to use the terminology from the wikipedia article?
If you want to have access to the user's history of visited links, then you're going to have to save them in a session. I've had a go at creating a decorator to do this.
breadcrumb.py:
import functools
import collections
import flask
BreadCrumb = collections.namedtuple('BreadCrumb', ['path', 'title'])
def breadcrumb(view_title):
def decorator(f):
#functools.wraps(f)
def decorated_function(*args, **kwargs):
# Put title into flask.g so views have access and
# don't need to repeat it
flask.g.title = view_title
# Also put previous breadcrumbs there, ready for view to use
session_crumbs = flask.session.setdefault('crumbs', [])
flask.g.breadcrumbs = []
for path, title in session_crumbs:
flask.g.breadcrumbs.append(BreadCrumb(path, title))
# Call the view
rv = f(*args, **kwargs)
# Now add the request path and title for that view
# to the list of crumbs we store in the session.
flask.session.modified = True
session_crumbs.append((flask.request.path, view_title))
# Only keep most recent crumbs (number should be configurable)
if len(session_crumbs) > 3:
session_crumbs.pop(0)
return rv
return decorated_function
return decorator
And here's a test application that demonstrates it. Note that I've just used Flask's built-in client side session, you'd probably want to use a more secure server-side session in production, such as Flask-KVsession.
#!/usr/bin/env python
import flask
from breadcrumb import breadcrumb
app = flask.Flask(__name__)
#app.route('/')
#breadcrumb('The index page')
def index():
return flask.render_template('page.html')
#app.route('/a')
#breadcrumb('Aardvark')
def pagea():
return flask.render_template('page.html')
#app.route('/b')
#breadcrumb('Banana')
def pageb():
return flask.render_template('page.html')
#app.route('/c')
#breadcrumb('Chimp')
def pagec():
return flask.render_template('page.html')
#app.route('/d')
#breadcrumb('Donkey')
def paged():
return flask.render_template('page.html')
if __name__ == '__main__':
app.secret_key = '83cf5ca3-b1ee-41bb-b7a8-7a56c906b05f'
app.debug = True
app.run()
And here's the contents of templates/page.html:
<!DOCTYPE html>
<html>
<head><title>{{ g.title }}</title></head>
<body>
<h1>{{ g.title }}</h1>
<p>Breadcrumbs:
{% for crumb in g.breadcrumbs %}
{{ crumb.title }}
{% if not loop.last %}»{% endif %}
{% endfor %}
</p>
<p>What next?</p>
<ul>
<li>Aardvark?</li>
<li>Banana?</li>
<li>Chimp?</li>
<li>Donkey?</li>
</ul>
</body>
</html>
i was trying to use the breadcrumb.py , but i was need to check:
if the new item "item = (flask.request.path, view title) " is already exist in the session crumbs, then i will delete all other items frome the index to the end, i do this for Avoid repetition in my session crumds.
flask.session.modified = True
item = (flask.request.path, view_title)
try:
if not item in session_crumbs:
session_crumbs.append(item)
else:
index = session_crumbs.index(item)
session_crumbs = session_crumbs[:index+1]
except:
pass
return rv
return decorated_function
return decorator

Categories