redirect while passing arguments - python

In flask, I can do this:
render_template("foo.html", messages={'main':'hello'})
And if foo.html contains {{ messages['main'] }}, the page will show hello. But what if there's a route that leads to foo:
#app.route("/foo")
def do_foo():
# do some logic here
return render_template("foo.html")
In this case, the only way to get to foo.html, if I want that logic to happen anyway, is through a redirect:
#app.route("/baz")
def do_baz():
if some_condition:
return render_template("baz.html")
else:
return redirect("/foo", messages={"main":"Condition failed on page baz"})
# above produces TypeError: redirect() got an unexpected keyword argument 'messages'
So, how can I get that messages variable to be passed to the foo route, so that I don't have to just rewrite the same logic code that that route computes before loading it up?

You could pass the messages as explicit URL parameter (appropriately encoded), or store the messages into session (cookie) variable before redirecting and then get the variable before rendering the template. For example:
from flask import session, url_for
def do_baz():
messages = json.dumps({"main":"Condition failed on page baz"})
session['messages'] = messages
return redirect(url_for('.do_foo', messages=messages))
#app.route('/foo')
def do_foo():
messages = request.args['messages'] # counterpart for url_for()
messages = session['messages'] # counterpart for session
return render_template("foo.html", messages=json.loads(messages))
(encoding the session variable might not be necessary, flask may be handling it for you, but can't recall the details)
Or you could probably just use Flask Message Flashing if you just need to show simple messages.

I found that none of the answers here applied to my specific use case, so I thought I would share my solution.
I was looking to redirect an unauthentciated user to public version of an app page with any possible URL params. Example:
/app/4903294/my-great-car?email=coolguy%40gmail.com to
/public/4903294/my-great-car?email=coolguy%40gmail.com
Here's the solution that worked for me.
return redirect(url_for('app.vehicle', vid=vid, year_make_model=year_make_model, **request.args))
Hope this helps someone!

I'm a little confused. "foo.html" is just the name of your template. There's no inherent relationship between the route name "foo" and the template name "foo.html".
To achieve the goal of not rewriting logic code for two different routes, I would just define a function and call that for both routes. I wouldn't use redirect because that actually redirects the client/browser which requires them to load two pages instead of one just to save you some coding time - which seems mean :-P
So maybe:
def super_cool_logic():
# execute common code here
#app.route("/foo")
def do_foo():
# do some logic here
super_cool_logic()
return render_template("foo.html")
#app.route("/baz")
def do_baz():
if some_condition:
return render_template("baz.html")
else:
super_cool_logic()
return render_template("foo.html", messages={"main":"Condition failed on page baz"})
I feel like I'm missing something though and there's a better way to achieve what you're trying to do (I'm not really sure what you're trying to do)

You can however maintain your code and simply pass the variables in it separated by a comma: if you're passing arguments, you should rather use render_template:
#app.route("/baz")
def do_baz():
if some_condition:
return render_template("baz.html")
else:
return render_template("/foo", messages={"main":"Condition failed on page baz"})

Related

class variable was caches in next request when use django-rest-framework renderer

I make use of uwsgi, django and django-rest-framework to develop one application.
I introduced one class variable in renderer class, this variable will be fill as one part of response.
the problem seems likes as following:
class xxxRenderer(xxxBase)
response_pb_msg = obj # it's one instance of protobuf message
def render():
if True:
self.response_pb_msg.items = []
else:
self.response_pb_msg.retCode = 100
self.response_pb_msg.otherXXXX = xxxx
In django logger handler, I access this class variable again like following:
xxxRenderer.response_pb_msg.ParseFromString(body)
after the first response, this class variable 'response_pb_msg' only has one property "retCode"
but the second response, it has three properties "retCode", "otherXXXX " and "items "
it's strange, the second response contain all content which was exist in the first response.
after a time, I re-wrote this class like following:
class xxxBaserender(xxRender)
def __init__():
if self.response_pb_msg_cls is not None and isinstance(self.response_pb_msg_cls, GeneratedProtocolMessageType):
self.response_pb_message = self.response_pb_msg_cls()
class xxxRenderer(xxxBaserender)
response_pb_msg_cls = msgName # the class of protobuf message
theoretically, the second class is ok. I tested, didn't duplicate that question.
Let's return to where we started
Every request finisehd, all resoure should be clean.
but I'm very puzzled with that problem, it seems that class variable not been released in uwsgi progress after response return.
I read “PEP 3333”, didn't get any valuable information.
I think I didn't fully understand class variaable, wsgi and web processing flow in python.
anyone can help me to understand this problem?
thanks vey much.

Flask redirect to url and pass query strings

I have a view that is defined like such:
#views.route('/issues')
def show_view():
action = request.args.get('action')
method = getattr(process_routes, action)
return method(request.args)
in my process_routes module, I would like to call this method, and pass query string values. I have the following code:
return redirect(url_for('views.show_view', action='create_or_update_success'))
I have a function in process_routes named create_or_update_success
I am getting
BuildError: ('views.show_view', {'action': 'create_or_update_success'}, None)
views is a blueprint. I can successfully call
/issues?action=create_or_update_success
In my browser.
What am I doing wrong?
The first part, views., has to reflect the first argument you give to your Blueprint() object exactly.
Don't be tempted to set that first argument to __name__, as that is likely to contain the full path of the module when inside a package. In your case I suspect that to be some_package.views rather than just views.
Use a string literal for the Blueprint() first argument instead:
views_blueprint = Blueprint('views', __name__)
so you can refer to url_for('views.show_view') without getting build errors.

Loop using app.route on Python

I'm trying to create several URLs on my serv thanks to a loop . The issue is that each function I create in a app.route can't have the same name than the others . And I don't know how to create different function names ...
Here is the code :
json_tweets = []
for line in open('C:\Users\Benjamin\Desktop\DashboardProject\last_rated_set.json',"r"):
json_tweets.append(json.loads(line,"ISO-8859-1"))
cashtag_tab = []
for tweet in json_tweets:
if not(tweet['cashtag'] in cashtag_tab) :
cashtag_tab.append(tweet['cashtag'])
for i in range(0,(len(cashtag_tab)-1)) :
var=cashtag_tab[i]
#app.route("/"+var)
def company(var) :
finance=Share(var)
datas = finance.get_historical('2014-01-01', '2014-12-31')
datas = json.dumps(datas, default=json_util.default)
return datas
I'm getting the error AssertionError : View function mapping is overwritting an existing endpoint function : company
This fails because Flask derives the endpoint name from the function by default, but it would anyway fail later because the function company requires an argument var and the route is not parameterised. The simplest option would be just checking the value inside the handler:
#api.route('/<var>')
def company(var):
if var not in cashtag_tab:
abort(404)
If you want all the routes to be in the routing map for any reason, I once needed a similar thing and came up with something like this:
def url_family(source, methods=('GET',)):
def decorator(f):
for entry in source:
# create a handler that delegates to your function
def view_func(entry=entry, **kwargs):
return f(entry, **kwargs)
endpoint = '{0}_{1}'.format(f.__name__, entry)
url = '/{0}'.format(entry)
api.add_url_rule(url,
methods=methods,
endpoint=endpoint,
view_func=view_func)
return decorator
Then you register the handlers as:
#url_family(cashtag_tab)
def company(var):
...
Assuming that you are using flask now, you should consider Custom URL Converter. Check links below
http://flask.pocoo.org/docs/0.10/api/#flask.Flask.url_map - url_map UrlConverter API
https://exploreflask.com/views.html#url-converters - example url converter
https://stackoverflow.com/a/5872904/3451543 - RegexConverter by Philip Southam
Anyway, specifying more details on your question is always helpful to get accurate answer :)

Flask: get current route

In Flask, when I have several routes for the same function,
how can I know which route is used at the moment?
For example:
#app.route("/antitop/")
#app.route("/top/")
#requires_auth
def show_top():
....
How can I know, that now route was called using /top/ or /antitop/?
UPDATE
I know about request.path I don't want use it, because the request can be rather complex, and I want repeat the routing logic in the function. I think that the solution with url_rule it the best one.
Simply use request.path.
from flask import request
...
#app.route("/antitop/")
#app.route("/top/")
#requires_auth
def show_top():
... request.path ...
the most 'flasky' way to check which route triggered your view is, by request.url_rule.
from flask import request
rule = request.url_rule
if 'antitop' in rule.rule:
# request by '/antitop'
elif 'top' in rule.rule:
# request by '/top'
Another option is to use endpoint variable:
#app.route("/api/v1/generate_data", methods=['POST'], endpoint='v1')
#app.route("/api/v2/generate_data", methods=['POST'], endpoint='v2')
def generate_data():
version = request.endpoint
return version
If you want different behaviour to each route, the right thing to do is create two function handlers.
#app.route("/antitop/")
#requires_auth
def top():
...
#app.route("/top/")
#requires_auth
def anti_top():
...
In some cases, your structure makes sense. You can set values per route.
#app.route("/antitop/", defaults={'_route': 'antitop'})
#app.route("/top/", defaults={'_route': 'top'})
#requires_auth
def show_top(_route):
# use _route here
...
It seems to me that if you have a situation where it matters, you shouldn't be using the same function in the first place. Split it out into two separate handlers, which each call a common fiction for the shared code.
One thing I have to add to the answers above is that
request.path preserves the url parameter value(s) passed while request.url_rule gives you the url_rule you defined without the passed parameter(s)
#app.route("/antitop/")
#app.route("/top/")
#requires_auth
def show_top():
request.path
request.url_rule
# -> both will give you "/antitop/" or "/top/"
....
#app.route("/antitop/<username>")
#app.route("/top/<username>")
#requires_auth
def show_top():
request.path
# -> gives you "/antitop/name" or ...
request.url_rule
# -> gives you "/antitop/<username>" or ...
....
Since you don't have any variable routes definey (yet!) you don't have to care but for the sake of saving you work and the headache in the future I'd still suggest using request.path.

BottlePy - How can I find the current route from within a hook?

I have the following hook in BottlePy:
#bottle_app.hook('before_request')
def update_session():
# do stuff
return
And some routes:
#bottle_app.route('/')
def index():
return render('index')
#bottle_app.route('/example')
def example():
return render('example')
From within update_session(), how can I determine which route is being called?
I have looked through the documentation to no avail, but surely this is possible?
The request has both a bottle.route and a route.handle entry, both contain the same value:
from bottle import request
print request['bottle.route']
This isn't documented; I had to find it in the bottle.py source. The value is a Route instance; it has both a .name and a .rule attribute you could inspect to determine which route was matched.
if request['bottle.route'].rule == '/':
# matched the `/` route.
For your specific example this is perhaps overkill, since you are only matching simple paths, but for more complex rules with regular expression rules this would work better than trying to match the request.path attribute (but it'd be a good idea to give your routes a name value).
from bottle import request
#bottle_app.hook('before_request')
def update_session():
print request.path
return
Should do what your asking for
You can then store routes in a dictionary.
my_routes = {"/":lambda: 5}
event = my_routes.get(request.path, lambda: None)
print event()

Categories

Resources