I'm pretty new in Tornado. Can I use something like below?
Class
class HomeHandler(BaseHandler):
def get(self):
return self.render("home.html")
def login(self):
return self.render("login.html")
Routes
(r"/", HomeHandler),
(r"/login", HomeHandler.login, dict(db=db)),
This is not working. I tried to use HomeHandler.login(), but am not sure how to pass the required references (which should be similar to self).
I appreciate your help. Thanks
No, that's not possible. Tornado chooses which method to call based on the HTTP request (get, post, etc), so it is not possible to specify an alternative method in the routing table. Use different classes instead (probably with a common base class).
Tornado uses the concept of "handlers", which, well, handle requests at a certain path. Handlers are classes. Internally Tornado selects a method from these classes corresponding to HTTP verb used in the request.
In your case, you have 2 paths: / and /login, let's call them "Home" and "Login' respectively. Now, you need to have 2 handlers: HomeHandler and LoginHandler and assign them to corresponding routes...
Routes:
(r"/", HomeHandler),
(r"/login", LoginHandler, {"db": db})
Handler classes:
class HomeHandler(BaseHandler):
def get(self):
# Will work for GET yoursite.com/, e.g. when opened in a browser
# The next line will render a template and return it to the browser
self.render("home.html")
class LoginHandler(BaseHandler):
def initialize(self, db):
# That `db` from route declaration is passed as an argument
# to this Tornado specific method
self.db = db
def get(self):
# Will work for GET yoursite.com/login, e.g. when opened in a browser
# You may use self.db here
# The next line will render a template and return it to the browser
self.render("login.html")
def post(self):
# Will work for POST yoursite.com/login, e.g. when the data
# from the form on the Login page is sent back to the server
# You may use self.db here
return
Related
I am trying something probably highly unorthodox: I need to pass an argument, that comes in via the url path to the class constructor of a class-based MethodView.
http://127.0.0.1:5000/child/my_id_string
I want to pass my_id_string to the following constructor as arg1.
My most promissing try was based on this question, but I need to use class-based views instead of functions. Unfortunately the logic behind this call is somewhat more complex than the example, i.e I cannot simply refactor the code to not use "my_id" in the constructor.
from flask import Flask, request
from flask.views import MethodView
BASE = 11
app = Flask('mybase')
class Child(MethodView):
def __init__(self, base, arg1=None):
self.base = base
print('some init process, where I need arg1...')
def get(self, arg1):
return f'Some operation with {str(arg1)}.'
app.add_url_rule(
'/child/<arg1>',
'child',
view_func=Child.as_view(
'child_view',
BASE,
arg1 = request.args.get('my_id')
),
methods=['GET',]
)
I get the following error with the snippet as is, because I figure the registration occurs before/without a specific request, is that correct?
Hope, someone is able to help. Thanks in advance!
RuntimeError: Working outside of request context.
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.
I am a little confused about your syntax of :
app = flask("mybase") :i use app = flask(__name__)
But this is what i would do.
#app.route("/child/<arg1>")
def x(arg1):
varArg1 = arg1
#now you have whatever is in the url will be passed into varArg1.
When develop an restful style API server with web.py micro framework . i have an issue about multiple URL with a handle class and http method funcation needs defferent arguments. for example:
URL:
url =['/api/users', 'User',
'/api/users/(\d+)$, 'User']
Class:
class User(object):
def GET(self, id=None):
Pass
def POST(self):
Pass
Issues:
When use postman call /api/uses/1 with POST method
Will happen an exception. How to fix it?
As suggested in a comment, make POST method's signature the same as GET:
def POST(self, id=None):
...
Your issue is due to the fact that your POST request /api/users/1 includes the final ID. That means webpy matches the pattern /api/users/(\d+)$, which is then handled by class User. If you GET that url, it goes to <User>.GET(), if you POST that url, it goes to <Users>.POST()... (DELETE goes to <User>.DELETE(), etc.)
Because the matching pattern includes a regex capture (\d+), that matched value will be passed as an additional argument to the function.... whichever function is called.
You can use a non-capturing regex: (?:\d+)$ which will require a match in the URL, but will not cause the matching value to be passed as a argument, so:
url = ('/api/users', 'User',
'/api/users/(?:\d+)$', 'User')
class User(object):
def GET(self, id=None):
pass
def POST(self):
pass
Now, /api/users and /api/users/1 will go to User class, and get handled by GET or POST depending on the request. Note that because you're no longer capturing the id your GET(self, id=None): still works, but will always have None for the id (because it's not captured!)
Most likely, what you want is the simple: make the arguments the same.
Or you can use flexible number of arguments:
def GET(*arg):
self = arg[0]
id = arg[1]
I want to design my web application to serve two different front-end templates depending on what domain the user enter my django application.
So, if the user enter aaa.com, it would serve front-end from app AAA_USA, but if the user enter from aaa.co.my, it would serve front-end from app AAA_MY.
What is the best way to do this? I was thinking of "detecting the current domain name" and then simply add an if-else statements in the View functions.
These two domains will be pointing to the same Nameservers that contains my Django app.
The way i did it is basically using the middleware (using session and detect the HTTP_HOST.
class SimpleMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before the view (and later middleware) are called.
# sets to show Taiwan or Indo version
# sets the timezone too
http_host = request.META['HTTP_HOST']
if(http_host == 'http://www.xxx.tw'):
request.session['web_to_show'] = settings.TAIWAN
request.session['timezone_to_use'] = settings.TAIWAN_TIMEZONE
else:
request.session['web_to_show'] = settings.INDO
request.session['timezone_to_use'] = settings.INDONESIA_TIMEZONE
response = self.get_response(request)
# Code to be executed for each request/response after the view is called.
return response
You can get a full url with "build_absolute_uri()":
def myview(request):
request.build_absolute_uri()
# http://localhost:8000/admin/store/product/
Then, this below can get the url without "admin/store/product/":
def myview(request):
request.build_absolute_uri('/')
# http://localhost:8000/
Then, this below can get the url without "/admin/store/product/":
def myview(request):
request.build_absolute_uri('/')[:-1]
# http://localhost:8000
Use
request.build_absolute_uri()
will retrive the full path:
es:
http://localhost:8000/test/
If you don't have access to the requests object, then you can use the sites framework:
from django.contrib.sites.shortcuts import get_current_site
domain = get_current_site(None)
This will return the site the Django is configured for (using the value saved in the django_site table of your database. (See: https://docs.djangoproject.com/.../sites/shortcuts/)
I'm trying to update an endpoint which I have defined previously as follows:
class NestedMessage(messages.Message):
foo = messages.StringField(1)
MyResource = endpoints.ResourceContainer(
message_types.VoidMessage,
param1=messages.StringField(1, required=True),
param2=messages.StringField(2),
param3=messages.MessageField(NestedMessage, 3)
)
class MyApi(remote.Service):
#endpoints.method(MyResource, messages.VoidMessage,
path='new', http_method='POST', name='new')
def new(self, request):
# ...
return messages.VoidMessage
I need to change from using a ResourceContainer to a Message class instead (it was unclear which one to use for POST methods).
So I try and update to this:
# NestedMessage unchanged
class NestedMessage(messages.Message):
foo = messages.StringField(1)
class MyMessage(messages.Message):
param1 = messages.StringField(1, required=True)
param2 = messages.StringField(2)
param3 = messages.MessageField(NestedMessage, 3)
class MyApi(remote.Service):
#endpoints.method(MyMessage, messages.VoidMessage,
path='new', http_method='POST', name='new')
def new(self, request):
# ...
return messages.VoidMessage
But when I try the endpoint in /_ah/api/explorer, it just shows a blank page. Checking the result of discovery.apis.getRest on my api, the new MyMessage class isn't listed, and the MyApi.new method is borked due to not having a resource container.
Renaming the method to something else (e.g. MyApi.create) works, but then it breaks the MyApi.new method.
Is there a way to "force" Cloud Endpoints to update all methods?
EDIT This is both on development (localhost) and when deploying.
EDIT 2 It seems the issue only happens with API Explorer. Using the updated endpoint (via the Javascript library for example) uses the working, updated method.
EDIT 3 No wait, I've updated two endpoint methods. Now, both of them are showing fine in API Explorer, but one of them still seems to be "broken" when used with the Javascript client library (i.e. POST payload is passed as URL query parameters, not as JSON body). The other is behaving correctly. What is going on?
I use the blobstoreuploadhandler and hence must return a self.redirect but I need to pass values to my template. How can I do it? If I can't use template values then I suppose I can use session variables and I've included the beaker session library but I can't understand how to access the session variables in django template. Any idea how I should do it?
I use default builtin django with google app engine and I can access session variables with a request handler but I don't understand how to do it in templates:
class Sessiontest(webapp.RequestHandler):
def get(self):
# Get the session object from the environ
self.session = self.request.environ['beaker.session']
# Check to see if a value is in the session
if 'counter' in self.session:
counter = self.session['counter'] + 1
self.session['counter'] = counter
else:
self.session['counter'] = 1
counter = 1
self.session.save()
self.response.out.write('counter: %d' % counter)
Thanks
Update/edit: My problem is almost exactly like this Accessing session variable in Django template with Google App Engine (Webapp) - Python but with the library beaker instead of gaeutilities
Update: Here's some of the code. we see that using HTTP GET to pass the values won't be very good since there's an anti-spam test that should hide the values:
def post(self, view):
message = ''
challenge = self.request.get('recaptcha_challenge_field').encode('utf-8')
response = self.request.get('recaptcha_response_field').encode('utf-8')
remoteip = os.environ['REMOTE_ADDR']
cResponse = captcha.submit(
challenge,
response,
CAPTCHA_PRV_KEY,
remoteip)
if cResponse.is_valid:
isHuman=True
else:#failed anti-spam test and can try again
isHuman=False
#Reprint the form
import util
template_values = {'isHuman':isHuman,'user' : users.get_current_user(),}
template_values.update(dict(current_user=self.current_user, facebook_app_id=FACEBOOK_APP_ID))
template_values.update(dict(capture=captcha.displayhtml(public_key = CAPTCHA_PUB_KEY, use_ssl = False, error = None)))
path = os.path.join(os.path.dirname(__file__), 'market', 'market_insert.html')
self.redirect("/ai") # Here the values aren't passed on and I must make a redirect
If you are doing a redirect you might have to redirect with the variables that you wish to keep in the GET string. So you redirect from
/myview/
to
/myview2/?variable1=value
However, I think you should really look to see why you are doing redirects. I tend to do them after a POST to a form, and if the user needs to be logged on, I redirect to a login screen with
/authentication/login/?next=/view/they/wanted/to/see
Otherwise you could keep things in cookies but its not the best way to proceed.
How about letting your class inherit from multiple classes, both requesthandler class and blobstoreuploadhandler, in that way you can both render your template with values with the functions in the requesthandler, and use the functions in blobstoreuploadhandler?
A class definition with multiple base classes looks as follows:
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
...
<statement-N>