POST query in Tornado with multiple parameters - python

Code:
class Telegram(tornado.web.RequestHandler):
def my_f(self,number):
return number
def get(self,number):
self.write( self.my_f(number))
application = tornado.web.Application([
(r"/number/(.*?)", Telegram),
])
Using this piece of code, i can trigger Telegram, providing it with something from the (.*?) part.
Question is: i need to make POST queries like:
/number/messenger=telegram&phone=3332223332211
so that I can grab messenger parameter and phone parameter, and trigger the right class with provided phone number (like Telegram with 3332223332211)

POST requests (usually) have a body, so if you want everything in the URL you probably want a GET instead of a POST.
The normal way to pass arguments is by form-encoding them. That starts with a ? and looks like this: /number?messenger=telegram&phone=12345. To use arguments like this in Tornado, you use self.get_argument("messenger") instead of an argument to the get() method.
A second way of passing parameters is to put them in the "path" part of the URL, without a question mark. This is when you use (.*?) in your routing pattern and an argument to get(). Use this when you want to avoid the question mark for some reason (usually aesthetics).
You can also combine the two: pass the messenger parameter in the URL as you've done here, and add ?number=12345 and use get_argument. But unless you really care about what your URLs look like, I recommend the first form.

Related

Django URL passing parameter

Would anyone please explain to me how to passing parameter in Django URL
I created view in view.py "def hours_ahead(request, offset)" to calculate the time ahead. Then on URL.py I call it with re_path(r'^time/plus/\d{1,2}/$', hours_ahead).
But I get the error message when I put the url http://127.0.0.1:8000/time/plus/2/
TypeError at /time/plus/2/
hours_ahead() missing 1 required positional argument: 'offset'
offset should be the data capture in the URL (identified within brackets in your URL pattern):
(r'^time/plus/(\d{1,2})/$', hours_ahead)
You configured the regular expression in your URL but didn't specify the parameter name that will be sent to your view function.
The following URL definition should work. Notice that the ?P part that is used to define the parameter that will capture the value matching the regular expression.
re_path(r'^time/plus/(?P<offset>\d{1,2})/$', hours_ahead)
Note 1: that if you're not really strict on the amount of hours that can be added, you can use simpler URL definition that just specifies an integer:
path('time/plus/<int:offset>/$', hours_ahead)
But that will allow a caller of your URL to add a huge amount of hours, as long as it fits the integer.
Note 2: Not really your question but if you think about correct API / interface design this can be important: what you're doing is an action, adding hours. That action is now triggered by an HTTP GET request. Actions should always be triggered by other HTTP methods such as POST, PATCH, etc.

How to change routes in Flask?

I have watched a tutorial on Flask and I can't seem to understand how does this code work
def my_home():
return render_template("./index.html")
#app.route('/<string:page_name>')
def html_page(page_name):
return render_template(page_name)```
Specifically /<string:page_name> is confusing to me, how does it understand what is page_name and redirect to that page?
Thank you!
The answer to this is in the magic of decorators and not flask itself. A decorator is a high level function which accepts a function and manipulates it accordingly. See the following example:
def route(func, user_path):
# internal flask mechanisms here
def callback(user_path):
return http.route(user_path, func)
return callback
#route("hello_world")
def render():
return "Hello World"
The decorator is taking your function as an input and performing some actions to correlate the path with your given input. This can obviously be used for many other purposes. For example, flask also allows an additional decorator to define the type of request allowed for the function, such as GET, POST, etc.
To answer your question, flask is accepting a URL parameter and generating the page based on that given parameter. This is known as dynamic routing and is used for database query purposes based on the route (though the given example is trivial). So if someone goes to page_name "John", you can use that value and template it in your html to dynamically say hi to John (and whomever else).
/<string:page_name>
means that Flask expects a customised string after your domain i.e.
www.yourdomain.com/anycustomisedstring
/<data_type:your_variable_name> i.e. /<integer:page_number>
in this case, your variable is passed as a parameter to your function. This function returns the site that is passed in the URL as a string

How to redirect user to 'view' without going through smartgrid in web2py

how do i redirect a registered user to his/her db.table.id 'view' without going through smartgrid in web2py?
i have tried using:
redirect(URL(f='first', args=['mydata/view', 'mydata/%s', %request.vars.name]))
where mydata is the view for my table db.mydata and 'first' is my function.
It always returns to the smartgrid interface.
There are two problems. First, the final URL argument must be the record ID, but it looks like you are instead using a name (i.e., request.vars.name). Second, by default, the grid uses signed URLs, so you must either disable the signatures (not recommended) or add a user signature to the URL you generate. So, the link should be something like this:
redirect(URL(f='first', args=['mydata', 'view', 'mydata', request.vars.id],
user_signature=True))
Also, note that in the args list, each element can (and generally should) be a separate URL arg. So, instead of ['mydata/view', ...], it should be ['mydata', 'view', ...].

Routes with trailing slashes in Pyramid

Let's say I have a route '/foo/bar/baz'.
I would also like to have another view corresponding to '/foo' or '/foo/'.
But I don't want to systematically append trailing slashes for other routes, only for /foo and a few others (/buz but not /biz)
From what I saw I cannot simply define two routes with the same route_name.
I currently do this:
config.add_route('foo', '/foo')
config.add_route('foo_slash', '/foo/')
config.add_view(lambda _,__: HTTPFound('/foo'), route_name='foo_slash')
Is there something more elegant in Pyramid to do this ?
Pyramid has a way for HTTPNotFound views to automatically append a slash and test the routes again for a match (the way Django's APPEND_SLASH=True works). Take a look at:
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/urldispatch.html#redirecting-to-slash-appended-routes
As per this example, you can use config.add_notfound_view(notfound, append_slash=True), where notfound is a function that defines your HTTPNotFound view. If a view is not found (because it didn't match due to a missing slash), the HTTPNotFound view will append a slash and try again. The example shown in the link above is pretty informative, but let me know if you have any additional questions.
Also, heed the warning that this should not be used with POST requests.
There are also many ways to skin a cat in Pyramid, so you can play around and achieve this in different ways too, but you have the concept now.
Found this solution when I was looking for the same thing for my project
def add_auto_route(config,name, pattern, **kw):
config.add_route(name, pattern, **kw)
if not pattern.endswith('/'):
config.add_route(name + '_auto', pattern + '/')
def redirector(request):
return HTTPMovedPermanently(request.route_url(name))
config.add_view(redirector, route_name=name + '_auto')
And then during route configuration,
add_auto_route(config,'events','/events')
Rather than doing config.add_route('events','/events')
Basically it is a hybrid of your methods. A new route with name ending in _auto is defined and its view redirects to the original route.
EDIT
The solution does not take into account dynamic URL components and GET parameters. For a URL like /abc/{def}?m=aasa, using add_auto_route() will throw a key error because the redirector function does not take into account request.matchdict. The below code does that. To access GET parameters it also uses _query=request.GET
def add_auto_route(config,name, pattern, **kw):
config.add_route(name, pattern, **kw)
if not pattern.endswith('/'):
config.add_route(name + '_auto', pattern + '/')
def redirector(request):
return HTTPMovedPermanently(request.route_url(name,_query=request.GET,**request.matchdict))
config.add_view(redirector, route_name=name + '_auto')
I found another solution. It looks like we can chain two #view_config. So this solution is possible:
#view_config(route_name='foo_slash', renderer='myproject:templates/foo.mako')
#view_config(route_name='foo', renderer='myproject:templates/foo.mako')
def foo(request):
#do something
Its behavior is also different from the question. The solution from the question performs a redirect, so the url changes in the browser. In the second form both /foo and /foo/ can appear in the browser, depending on what the user entered. I don't really mind, but repeating the renderer path is also awkward.

What is the best REST implemenation when using tornado RequestHandlers

I would like to define a REST API with a general pattern of:
mysite.com/OBJECT_ID/associations
For example:
mysite.com/USER_ID/vacations - manage a users vacation
mysite.com/USER_ID/music - manage music in the user's music library
mysite.com/PLAYLIST_ID/music - manage music in the context of the given playlist
I am using tornado on the server side and looking for suggestions about how to define the RequestHandlers for this API. For instance, I want to define a handler like:
/([0-9,a-z,A-Z,-]+)/music",MusicHandler), but I'm stuck on the implementation of MusicHandler, which needs to know if the object specified by in the uri supports music in the first place i.e. how to guard against a call like
mysite.com/LOCATION_ID/music
Where locations have no associations with music.
Is the best fix to modify the api to include the type i.e.:
mysite.com/users/USER_ID/music or
mysite.com/playlists/PLAYLIST_ID/music
and then a separate handler for each:
/users/([0-9,a-z,A-Z,-]+)/music",UserMusicHandler),
/playlists/([0-9,a-z,A-Z,-]+)/music",PlaylistMusicHandler)
That doesn't seem right, but I don't really understand how to make this work. I'm sure this is a simple issue, I am new to python and tornado.
First of all, to guard against mysite.com/LOCATION_ID/music I would create differences between all of your id's. For instance, have LOCATION_ID be a 32 character string, and PLAYLIST_ID 34, etc. This way you can check for the string length as soon as the handler is called.
Alternatively, you can use regular expression groups to catch it right in the URI and then define different handlers for each. (Also, your ID should probably be after all of the static text in the URI, just for good convention). For instance, if your PLAYLIST_ID is a UUID and you LOCATION_ID is a string:
(r"/music/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", PlaylistMusicHandler), #playlistID
(r"/music/([A-Za-z0-9]+)", LocationHandler), #locationID
if not self.db.get("SELECT 1 FROM objects WHERE music_id = %s", object_id):
raise HTTPError(404, "Music object %s not found" % name)
FWIW a mysite.com/music/MUSIC_ID scheme makes more sense to me.

Categories