Consider I want to create a singleton object for each user accessing a particular feature in the website. This object is not a Model.
class NavApi:
__instance = None
#staticmethod
def get_instance():
""" Static access method. """
if NavApi.__instance is None:
Client()
return NavApi.__instance
In views file
#csrf_exempt
def get_folder_tree(request):
if request.method == "POST":
nav_api = NavAPI.get_instance()
folders = nav_api.listing_folders(request.POST.get('id'))
return render(request, "folder_tree.html", {'folders': folders, 'page1': False})
#csrf_exempt
def get_prev_folder_tree(request):
if request.method == "POST":
nav_api = NavAPI.get_instance()
page1,folders = nav_api.listing_prev_folder_tree()
return render(request, "folder_tree.html", {'folders': folders,'page1':page1})
The reason for using Singleton is that the class object has few members which defines the state of the folder/contents/current folder_id etc. And it should not be created for every view. It needed to be reused
But when I tried to run it as public, using ngrok and shared the linked to my friend, and testing the navigation features,
We ended up using the same singleton object. When I was browsing contents of Folder A, and he was browsing contents of Folder B, we ended up recieving contents of the same folder(either A or B).
How to overcome this?
Python is not PHP... In a typical production setup, your app will be served by many long-running processes, so you can NOT expect to reliably use process memory as a way to persist global state (a singleton IS global state) from request to request - you can have the same user having two consecutive requests served by different processes and a same process serving requests for two different users.
If you want to maintain per-user state between requests, you have to use some shared storage, the very obvious solution here being sessions.
Can I get any reference to a resource which deals a similar case?
Using sessions ? That's fully documented
Oh and yes: if all you're doing is to navigate thru folders, you are badly misusing http verbs:
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Here you are just reading resources, so you want to use GET requests.
Related
While doing the Miguel Grinberg's Flask Web Development, I got stuck while testing the gravatar code,
def test_gravatar(self):
u = User(email='john#example.com', password='cat')
with self.app.test_request_context('/'):
gravatar = u.gravatar()
gravatar_256 = u.gravatar(size=256)
gravatar_pg = u.gravatar(rating='pg')
gravatar_retro = u.gravatar(default='retro')
with self.app.test_request_context('/', base_url='https://example.com'):
gravatar_ssl = u.gravatar()
self.assertTrue('http://www.gravatar.com/avatar/' +
'd4c74594d841139328695756648b6bd6'in gravatar)
self.assertTrue('s=256' in gravatar_256)
self.assertTrue('r=pg' in gravatar_pg)
self.assertTrue('d=retro' in gravatar_retro)
self.assertTrue('https://secure.gravatar.com/avatar/' +
'd4c74594d841139328695756648b6bd6' in gravatar_ssl)
What does app.test_request_context() do and how is it different from app_context()?
Why do we even need to call with self.app.test_request_context('/')? Also, what changes can we do to shift the call to app.test_request_context() in SetUp()?
There's plenty of reading to do on the subject, so start with the documentation: app_context, test_request_context, and you can always double-check the code: app_context and test_request_context. In addition, here's an article discussion Flask's contexts.
That's a lot of links, so for a break-down:
We can see that app_context creates a new application context, while test_request_context creates a new request context. Application contexts are created in two situations: manually with app_context and when a request context is created, which, in turn, is created with test_request_context or at the beginning of the request.
So when a request comes into your application, a RequestContext is created. The creation of this object creates an application context.
Why test_request_context? You need that context to access the application when working outside of a context created by a request, like proxies that you probably recognize, like current_app, request, g, and session. Going down into the code, when you create a RequestContext with test_request_context instead of request_context, you're getting a EnvironBuilder object.
Check out tbicr 's answer here.
Specifically, this snippet of code
gravatar = u.gravatar()
gravatar_256 = u.gravatar(size=256)
gravatar_pg = u.gravatar(rating='pg')
gravatar_retro = u.gravatar(default='retro')
requires request context since it needs to access 'request' variable.
The definition of gravatar method in User Model needs 'request' variable.
def gravatar(self, size=100, default='identicon', rating='g'):
if request.is_secure: # here
url = 'https://secure.gravatar.com/avatar'
else:
url = 'http://www.gravatar.com/avatar'
hash = self.avatar_hash or hashlib.md5(self.email.encode('utf-8')).hexdigest()
return '{url}/{hash}?s={size}&d={default}&r={rating}'.format(url=url, hash=hash, size=size, default=default, rating=rating)
#app.route('/a', methods=['GET', 'POST'])
def a():
form = data(request.form)
if form.validate_on_submit():
job = Job()
job.title = form.title.data
return redirect(url_for('users.b'))
#app.route('/b', methods=['GET', 'POST'])
def b():
#access here the job.title previous defined
I know that I can pass parameters to url_for, but isn't what i am looking for. Basically access the previous defined object attributes. How can I do that?
HTTP is a stateless connection, meaning a user being redirected to /b from /a will only be able to pass information via HTTP headers, cookies and URL parameters.
To solve this particular problem, you'll want to save the information set in job.title into a database on the host (i.e. Using SQLAlchemy in Flask). Then, you can pass the database ID of the new entry into the url_for parameter in /a so that it's redirected to some URL with this parameter set. (i.e. /b?user_id=123). Be aware there are multiple security issues you'll need to be aware of, since the user can just change the ID themselves.
There are lots of ways to do this. You may want to use the Flask-WTF addon to handle some of this for you.
Here's some snippets on handling sessions in Flask.
I am working on a google app engine (gae) project in python which has the following structure:
class LoginHandler(webapp2.RequestHandler):
def get(self):
...#check User-> DB access
def post():
...#check User-> DB access
class SignupHandler(webapp2.RequestHandler):
def get(self):
...#check User-> DB access
def post():
...#check User-> DB access
class Site1Handler(webapp2.RequestHandler):
def get(self):
...#check User-> DB access
def post():
...#check User-> DB access
class Site2Handler(webapp2.RequestHandler):
def get(self):
...#check User-> DB access
def post():
...#check User-> DB access
class ...
application = webapp2.WSGIApplication([('/login', LoginHandler),
('/signup',SignupHandler),
('/site1', Site1Handler),
('/site2', Site2Handler),
...,
],
debug=True)
Every user who wants to use this application has to be logged in.
Therefore on the login-site and the signup-site a cookie value with an user_id is set.
So lets imagine this app has 100 URLs and the corresponding 100 Site...Handlers() implemented.
Than for every get()/post() call I first get the user_id from the cookie and check in the database if this user exists and if it is valid.
So if the user clicks on 20 sites the app accesses 20 times the db to validate the user.
I am sure there is a better way and I would be glad if someone could show me how to do this.
I have already seen someone inherited his own Handler from webapp2.RequestHandler
which would than look like:
class MyHandler(webapp2.RequestHandler):
def initialize(self, *a, **kw):
webapp2.RequestHandler.initialize(self, *a, **kw)
uid = self.request.cookies.get('user_id')
self.user = uid and User.all().filter('userid =', uid).get()
class LoginHandler(MyHandler):
def get(self):
...#if self.user is valid -> OK
def post():
...#if self.user is valid -> OK
...
And here it is getting confusing for me.
Consider two or more people accessing the application concurrently. Will then User1 see data of User2 because self.user is initialized with data from User2?
I also concidered using a global variable to save the current user. But here the same problem if two users access the app concurrent.
I also found the webapp2.registry functionality which seemed to me the same like a global dictionary. And here also the problem of two or more users accessing the app at the same time.
Could someone please show me how to do it right? I am very new to gae and very happy for every hint in the right direction.
(Maybe Memcached is the solution. But I am more interested in a review of this check if user is valid pattern. So what would be best practice to do this?)
Assuming that you are using NDB and validating your user by getting a User object via a key/id - it will be automatically cached in memcache as well as in current local instance's memory, so your route handlers won't be calling Datastore with every single request, this is all done automatically, no extra coding required. If for validation / getting the user object you are using a query - the result won't be automatically cached but you can always manually cache it and verify the user via cache first and if the cache doesn't exist only then query Datastore, caching the results for the next request.
See more here.
If you are using webapp2's Sessions with signed/secure cookies then the data in those cookies, including the fact that the user is validated (which you previously set when when validating the user the first time) can be trusted, as long as you use long and randomly generated secret_key, that is kept secret and thus, just like with cache, you first check whether the user is validated in the cookie and if not, you ask Datastore and save the result in the session cookie for the next request. See more here.
Either way, you don't have to repeat your validation code in every single handler like you are showing in your example. One way of fixing it would be using decorators which would make your validation reuse as simple as placing #login_required before your get method. See more info here and take a look at the webapp2_extras.appengine.users file to get an idea how to write your own, simmilar decorator.
So ... using the Google App Engine User service.
Should I create a local user object:
my_user = users.get_current_user()
if not my_user:
self.redirect(users.create_login_url(self.request.uri), abort=True)
return
person = Person.get_current(my_user.user_id()) #Here
or access the user object from the users service anytime? :
my_user = users.get_current_user()
if not my_user:
self.redirect(users.create_login_url(self.request.uri), abort=True)
return
#... code ...
person = Person.get_current(users.get_current_user().user_id()) #And here
or something else? :
helping useres :-)
and of course why. Is usage of users service costly in resources?
A locally scoped user object should be fine for each request.
Make sure my_user is local to your thread and the current request:
if it's shared between separate requests, there's no guarantee that it's really the same user issuing the request, unless you have some separate session validation.
different threads can be handling different request, in which case you run into the above problem.
A local call is always better as a call that triggers many method calls. The efficiency gain depends on the frequency your code is calling it. For 2 calls it's okay.
I'm trying to make the currently logged in username available in all templates. I can receive it from pyramid.security.authenticated_userid, but to do that I need the request object. I tried to go via the BeforeRender subscription, but as far as I can tell, the request in not passed to that callback.
How else can I make the username available everywhere (or in the base template really)?
A common method is to attach the user object to the request via this cookbook recipe.
Another possibility is to attach it as you suggested using a BeforeRender subscriber. The request is available from the event:
def add_renderer_globals(event):
request, context = event['request'], event['context']
event['user'] = authenticated_userid(request)