url_for() parameter was ignored in flask - python

My route method is:
#app.route('/movie/')
def movie(page_num=1):
#...detail skipped...
And my template is:
<li>{{ page_num }}</li>
When I click the link, the address bar shows "127.0.0.1:5000/movie/?page_num=5",but the pagination.page shows it is still page 1.
Why the parameter was ignored and how can I fix it?

Since you skipped the code of your function it's hard to say what's wrong. But I suspect that you just don't catch GET parameters correctly. To do this you can either use variable rules with dynamic name component in your route; or access parameters submitted in the URL with request.args.get.
Here's a minimal example showing boths methods:
from flask import Flask, url_for, request
app = Flask(__name__)
#app.route('/')
def index():
link = url_for('movie',page_num=5)
return "<a href='{0}'>Click</a>".format(link)
#app.route('/index2')
def index_get():
link = url_for('movie_get',page_num=5)
return "<a href='{0}'>Click</a>".format(link)
#app.route('/movie/<page_num>')
def movie(page_num=1):
return str(page_num)
#app.route('/movie_get')
def movie_get():
param = request.args.get('page_num', '1')
return str(param)
if __name__ == '__main__':
app.run(debug=True)

Related

Redirecting in Flask with path from url

I am running into a problem trying to redirect in Flask using the following:
#views.route('/dash_monitoring/<path:url>')
#login_required
def monitoring_page(url):
return redirect("/home/dash_monitoring/{}".format(url))
The url in <path:url> is in the format https://somesite.com/detail/?id=2102603 but when I try to print it in the function, it prints https://somesite.com/detail only without the id part,so it obviously redirects to /home/dash_monitoring/https://somesite.com/detail instead of /home/dash_monitoring/https://somesite.com/detail/?id=2102603.
What should I do so it keeps the id part and redirects to the right url?
You can use request.url and imply string manipulation:
#views.route('/dash_monitoring/<path:url>')
#login_required
def monitoring_page(url):
parsed_path = request.url.split('/dash_monitoring/')[1]
#return the parsed path
return redirect("/home/dash_monitoring/{}".format(parsed_path))
Alternatively, you can iterate through request.args for creating query string and construct path with args
#views.route('/dash_monitoring/<path:url>')
#login_required
def monitoring_page(url):
query_string = ''
for arg,value in request.args.items():
query_string+=f"{arg}={value}&"
query_string=query_string[:-1] # to remove & at the end
path=f"{path}?{query_string}"
#return the parsed path
return redirect(f"/home/dash_monitoring/{path}")
I hope this helps :)
This has an easy solution, we use the url_for function:
from flask import Flask, redirect, url_for
app = Flask(__name__)
#app.route('/<name>')
def index(name):
return f"Hello {name}!"
#app.route('/admin')
def admin():
return redirect(url_for('index',name = 'John'))
if __name__ == '__main__':
app.run(debug = True)
In my code we firs import redirect and url_for.
We create 2 routes index and admin.
In index route we output a simple response with the named passed to the url. So if we get example.com/John it will output Hello John!.
In admin route we redirect the user to index route because it's not the admin (This is a simple example that can you can model with what you want). The index route needs a name so we pass inside the url_for function some context so it can desplay the name.

Flask redirect(url_for) with arguments

I'm new to building web apps using Flask and having trouble using redirect(url_for)
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
def getSomeList(paramsFromHTML):
return someList
#app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
myData = getSomeList(paramsFromHTML)
return redirect(url_for("show_data", this_data=myData))
else:
# Show the default page for GET requests
return render_template("welcome.html")
#app.route("/show_data", methods=["GET", "POST"])
def show_data(this_data):
return render_template("show_data.html", data=this_data)
Once I get some details from HTML in my main index page, I need to route it to the show_data view function.
The function has a parameter (this_data). However, there is no parameter in the route itself - like "/show_data/<string:something>" It is just "/show_data"
I get the below error when trying this.
TypeError: show_data() missing 1 required positional argument: 'this_data'
Is it mandatory to have some kind of a parameter in the url route as well?
Is there any work around I can try for my use case?
I was able to get this working after removing the args part (this_data) from my show_data function and use the below to get the value -
this_data = request.args.get('data')

Getting user input then implementing it inside a function

So what I'm doing here is trying to get the user to type in a keyword then using that input to customize a certain search query and then displaying the result.
I would like to attach that input and make it readable inside a function, I've tried making a second function to fetch the input then calling it inside the other function but that doesn't seem to work.
Here is my flask code
#app.route('/')
def hello_world():
keyword = 'KEYWORD' **I need to make this an input by the user**
url = ('https://ajax.googleapis.com/ajax/services/search/news?v=1.0&q='+ keyword + '&rsz=8')
response = requests.get(url)
articles = response.json()
return render_template('index.html', articles = articles, enumerate=enumerate)
#app.route('/', methods = ['POST'])
def form():
get_keyword = request.form['keyword']
return get_keyword
if __name__ == '__main__':
app.run(debug=True)
And this is my index.html
<form method="post" action="/">
<input type="text" name="keyword">
</form>
#app.route('/', methods = ['POST'])
def hello_world():
keyword = request.form['keyword']
url = ('https://ajax.googleapis.com/ajax/services/search/news?v=1.0&q='+ keyword + '&rsz=8')
response = requests.get(url)
articles = response.json()
return render_template('index.html', articles = articles, enumerate=enumerate)
This should solve your problem. You need to make your first app.route a post request and the inside of this request simply request from here. No need for the extra post function.
This is an example from flask's documentation. It is different but uses the exact same logic and will help you understand what you were doing wrong.
http://flask.pocoo.org/docs/0.10/tutorial/views/#tutorial-views

Flask: Trouble Accessing View (URL not found on server)

I'm trying to add another view to my Flask app. My app/views.py looks like this:
from flask import render_template
from app import app
from helpfulFunctions import *
def getRankingList():
allPlayers = main()
return allPlayers
def displayLimitedNumberOfPlayers(limit):
allPlayers = main()
allPlayers[0] = limitPlayers(allPlayers[0], limit)
allPlayers[1] = limitPlayers(allPlayers[1], limit)
return allPlayers
#app.route("/")
#app.route("/index")
def index():
rankingList = getRankingList()
return render_template('index.html', title='Home', rankingList = rankingList)
#app.route("/top100")
def top100():
rankingList = displayLimitedNumberOfPlayers(100)
return render_template('top100.html', rankingList = rankingList)
if __name__ == '__main__':
app.run(debug=True)
I've tried to mimic how the Miguel Grinberg tutorial defines routes for / and for /index. I've created a view called top100.html in my templates folder, where the "index.html" file also lives. However, when I try to hit localhost:5000/top100.html, I get:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
So it seems like Flask doesn't think that URL has a view associated with it...but I'm not sure why.
Any idea?
Thanks for the help,
bclayman
There is no view top100.html in your code.You can do either of these
localhost:5000/top100
OR
change #app.route("/top100") to #app.route("/top100.html")
The route (or url) is specified in the #app.route() definition, so you should visit localhost:5000/top100.
The render_template top100.html is only referenced internally within Flask to specify the template used. Really, this page could be named anything and does not have to be named in any similar way to the route...it just has to match the template file used to build the page served at that url.

Bad Request Error with flask, python, HTML, unusual initialization behavior with flask.request.form

I'm writing a web-app using flask, python and HTML. My issue is that the first time I load the a webpage, I get the following error
Bad Request The browser (or proxy) sent a request that this server
could not understand.
I'm able to get the page to load eventually by "tricking" first running it without any flask.request.form calls, and then putting them back in (details below). Something must be going wrong in my initialization. I'm new to flask and using python with HTML.
Assume I'm working from a directory called example. I have a python script called test.py and an HTML template called test.html with the following directory structure:
\example\test.py
\example\templates\test.html
My python script test.py is:
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
result = flask.request.form['result']
return flask.render_template('test.html', result=result)
# return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
and my HTML in test.html is
<html>
<head>
</head>
<body>
<form action="/" method="post">
Enter something into the box:
<input type="text" name="result"/><br>
<input type="submit" value="Execute!"/>
</form>
</body>
</html>
Steps to reproduce the error
1: Run the test.py script, and open up the URL in a browser
Running on http://127.0.0.1:5000/
You should see the following error
Bad Request The browser (or proxy) sent a request that this server
could not understand.
2: Comment out the first 2 lines of the def get(self) function and uncomment the 3rd line of the def get(self) function so that test.py looks like this
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
# result = flask.request.form['result']
# return flask.render_template('test.html', result=result)
return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
3: Refresh the URL, and you will see that things work (though I ultimately want to be able to return the value of result
4: Now, switch the lines that are commented out again. I.e, uncomment the first 2 lines of the def get(self) function and comment out the 3rd line of the def get(self) function so that test.py looks like this
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
result = flask.request.form['result']
return flask.render_template('test.html', result=result)
# return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
5: Refresh the URL and now you see things will be working as desired.
This is just a toy example illustrating the real problem exhibiting this weird behavior of how I have to "trick" my browser into showing me this webpage. The
The issue here is that you are attempting to access POSTed variables in a method that will only handle GET requests. When you attempt to access a query string or POST parameter that is not set Flask will, by default, raise a BadRequest error (because you are asking for something that the person hitting the page did not supply).
What happens if the key does not exist in the form attribute? In that case a special KeyError is raised. You can catch it like a standard KeyError but if you don’t do that, a HTTP 400 Bad Request error page is shown instead. So for many situations you don’t have to deal with that problem.
If you need to access a variable from either request.args (GET) or request.form (POST) and you don't need it to be set use the get method to get the value if it is there (or None if it is not set.
# Will default to None
your_var = request.form.get("some_key")
# Alternately:
your_var = request.form.get("some_key", "alternate_default_value")
Here's an alternate way of structuring your code:
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
app.debug = True
class View(flask.views.MethodView):
def get(self):
"""Enable user to provide us with input"""
return self._default_actions()
def post(self):
"""Map user input to our program's inputs - display errors if required"""
result = flask.request.form['result']
# Alternately, if `result` is not *required*
# result = flask.request.form.get("result")
return self._default_actions(result=result)
def _default_actions(self, result=None):
"""Deal with the meat of the matter, taking in whatever params we need
to get or process our information"""
if result is None:
return flask.render_template("test.html")
else:
return flask.render_template("test.html", result=result)
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
if __name__ == "__main__":
app.run()

Categories