I want to create an object at the beginning of the handling of a request and keep it associated during the whole life time of the request. In the context of a request it should behave like a singleton, so each request gets one and not more than one of them.
Now I'm thinking I could make it attach itself to the request variable in it's __new__ method, that would work, but I'm unsure if there isn't a nicer way to do this than to clutter the request variable?
class AuthScheme(object):
context_attribute = 'auth_scheme'
# inside the context of a request behave like a singleton
def __new__(cls, request, *args, **kwargs):
if not hasattr(request, cls.context_attribute):
# instantiante via base class only if there is no instance
# for this request yet
instance = super(AuthScheme, cls).__new__(
cls, request, *args, **kwargs)
setattr(request, cls.context_attribute, instance)
# return instance from request context
return getattr(request, cls.context_attribute)
I'm also worried about collisions if something else would try to create a property of the request object with the same name. Is there a nicer way of doing this?
g is what you are looking for.
from flask import g
You can add any attributes you want to g. It's created anew for each request. One common use is for storing a reference to the database.
#app.before_request
def before_request():
g.db = connect_db()
#app.teardown_request
def teardown_request(exception):
db = getattr(g, 'db', None)
if db is not None:
db.close()
Related
#property
def get_maca(self, request):
if request.user.name == "example":
return self
I want to do something like this. If the user name is example return that object.
How to access the request like this?
The standard way is to pass the request, or in your case just the user object, from the view/router all the way down to the models.
This gets very quickly out of hand in a larger project, so my approach is to use thread local to save some of the request context that I like to have available across the whole project. The thread local storage will keep data available inside a single thread, without it being accessible from other threads - great if you're gonna run the Django app on a production server.
Start with the local storage:
from threading import local
_active_user = local()
def activate_user(user):
if not user:
return
_active_user.value = user
def deactivate_user():
if hasattr(_active_user, "value"):
del _active_user.value
def get_user():
"""Returns `(is_anonymous, user)` ."""
active_user = getattr(_active_user, "value", None)
if active_user and active_user is not AnonymousUser:
try:
return False, active_user
except AttributeError:
pass
return True, None
Now that's all good, you can use this manually. Calling activate_user will make you be able to call get_user in any place in your project. However, this is error prone - if you forget to call deactivate_user, the user object will still be available to the next coming request.
The rest of the answer is to show how to make things automatic.
Let's first make a middleware to clean up by calling deactivate_user after every single request.
class ThreadCleanupMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
# Executed for each request/response after
# the view is called.
deactivate_user()
return response
Add a path to the ThreadCleanupMiddleware to the end of your settings.MIDDLEWARE list.
Finish up with a view mixin that activates the user automatically (that's for class based views; if you're using functional views, it would be a decorator instead):
class ContextViewSetMixin:
def initial(self, request, *args, **kwargs):
super().initial(request, *args, **kwargs)
if request.user.is_authenticated:
activate_user(request.user)
class ContextModelViewSet(ContextViewSetMixin, viewsets.ModelViewSet):
pass
I am overriding some methods of a popular package, django-activity-stream (I think the package is mostly irrelevant to this question).
from app/urls.py I call TeamJSONActivityFeed
urlpatterns = [
...
url(_(r'^feeds/organization/(?P<organization_id>.+)$'), TeamJSONActivityFeed.as_view(name='organization_stream')),
...
]
TeamJSONactivityFeed then calls 'pass', which I am not too familiar with, and inherits from two other classes, OrganizationStreamMixin and JSONActivityFeed.
from rest_framework.authentication import TokenAuthentication
class TeamJSONActivityFeed(OrganizationStreamMixin, JSONActivityFeed):
"""
JSON feed of Activity for a custom stream. self.name should be the name of the custom stream as defined in the Manager
and arguments may be passed either in the url or when calling as_view(...)
"""
authentication_classes = (TokenAuthentication,)
pass
My issue is that I cannot seem to access/pass the request object in/to these inherited classes. How would I go about passing this in? Right now, self.request.user and request.user are AnonymousUser objects.
class OrganizationStreamMixin(object):
name = None
def get_object(self,request):
# this is printing Anonymous User
pprint(str(self.request.user))
pprint(str(request.user))
return
def get_stream(self):
return getattr(Action.objects, self.name)
def items(self, request, *args, **kwargs):
return self.get_stream()(*args[1:], **kwargs)
class JSONActivityFeed(AbstractActivityStream, View):
"""
Feed that generates feeds compatible with the v1.0 JSON Activity Stream spec
"""
def dispatch(self, request, *args, **kwargs):
for i, v in kwargs.items():
print (" ", i, ": ", v)
return HttpResponse(self.serialize(request, *args, **kwargs),
content_type='application/json')
def serialize(self, request, *args, **kwargs):
pprint(str(self.request.user))
items = self.items(request, *args, **kwargs)
return json.dumps({
'totalItems': len(items),
'items': [self.format(action) for action in items]
})
Note: I am a bit of a django/python noob, but I am sure I am calling this properly from the front end. Similar requests have access to the request user.
I think there's a bit of confusion. You do have access to the request object otherwise it would raise an error for trying to access .user on None. If you're concerned about it being an AnonymousUser instance, then authenticate before accessing that view. If you need to prevent AnonymousUser instances from being able to access that view, then wrap the view with the login_required decorator.
Edit
You're overriding the dispatch method without calling super. That could be the problem.
I use wtforms_sqlalchemy in my pyramid apps and define several QuerySelectFields. The query factory uses the imported DBSession object to make the query.
from wtforms.form import Form
from wtforms_sqlalchemy.fields import QuerySelectField
from myapp.models import DBSession, MyModel
def mymodel_choices():
choices = DBSession.query(MyModel)
return choices
class MyForm(Form):
mymod = QuerySelectField(u'Field', query_factory=mymodel_choices)
Pyramid 1.7 introduced a new SQLAlchemy scaffold which attaches the db session object to each request. Using the new scaffold mymodel_choices has to use request from my view to access the db session. The field doesn't have access to the request object though, and doesn't know to call the factory with it.
My idea was to update query_factory directly from the view but that doesn't seem to be a logical way to do it. How can I use QuerySelectField when the db session is part of the request object?
query_factory only specifies the default query to use, but QuerySelectField will prefer the query property if it is set. This is useful for Pyramid, which discourages interacting with threadlocal directly.
Change the factory to accept a db session. Set query to the result of calling your factory with the request's db session.
def mymodel_choices(session):
return session.query(MyModel)
f = MyForm(request.POST)
f.mymod.query = mymodel_choices(request.db_session)
Since this is a bit inconvenient, you can create a subclass of Form that takes the request, pulls out the appropriate form data, and calls each QuerySelectField's query factory with the request.
class PyramidForm(Form):
def __init__(self, request, **kwargs):
if 'formdata' not in kwargs and request.method == 'POST':
kwargs['formdata'] = request.POST
super().__init__(**kwargs)
for field in self:
if isinstance(field, QuerySelectField) and field.query_factory is not None and field.query is None:
field.query = field.query_factory(request.db_session)
class MyForm(PyramidForm):
...
f = MyForm(request)
You can try something like this (although it's not the cleanest solution)
from myapp.models import MyModel
from pyramid import threadlocal
def mymodel_choices(request=None):
request = request or threadlocal.get_current_request()
choices = request.DBSession.query(MyModel)
return choices
for more details please see: http://docs.pylonsproject.org/projects/pyramid/en/latest/api/threadlocal.html
Is there a way to internally pass on the handling of a request from one RequestHandler subclass to another? Basically, what I would like to do is, from the get method of a RequestHandler (well, a subclass of RequestHandler), dispatch the task of handling the request to another handler (subclass of RequestHandler), whose name is determined by a value fetched from the datastore (I'm using GAE, but that is irrelevant to this problem). The code would look something like this:
class Dispatcher(RequestHandler):
def get_handler(some_id):
handler_name = get_handler_name(some_id) # fetches from datastore/etc.
return getattr(my_module, handler_name)
def get(self, some_id, *args, **kwargs):
handler = get_handler(some_id) # e.g., handler could be a HandlerA
# Not a real function, just to describe what to do:
# invokes get method of HandlerA (if handler == HandlerA)
dispatch_to_handler(handler, self, *args, **kwargs)
def post(self, some_id):
handler = get_handler(some_id)
dispatch_to_handler(....) # dispatches to post method of the handler
class HandlerA(RequestHandler):
def get(self, *args, **kwargs):
do_stuff()
def post(...):
do_post_stuff()
The big issue is that I need to somehow pass self and the positional and keyword arguments on to the other handler (HandlerA in this example), as self contains the request, response, session, authentication, and other data, which HandlerA (or whatever the handler may be) needs in order to process the request.
Try it this way:
def get(self, some_id, *args, **kwargs)
handler_cls = get_handler(some_id)
handler = handler_cls(self.request, self.response)
return handler.dispatch()
I am trying to define a base request handling class so that the webapp pages may inherit some basic methods and variable which otherwise would be required to be repeatedly be defined for each page of the application. A sort of similar functionality like django preprocessors. This is my base class from which other pages inherit:
class BasePage(webapp.RequestHandler):
def __init__(self):
self.user = users.get_current_user()
self.template_values = {
'user': self.user,
'environ': self, #I don't like the idea of passing the whole environ object to a template
##The below three functions cannot be executed during _init_ because of absence of self.request
#'openid_providers': self.openid_providers(),
#'logout_url': self.get_logout_url(),
#'request': self.get_request(),
}
##A sort of similar functionality like render_to_response in django
def render_template(self, template_name, values = None, *args, **kwargs):
#PATH is the directory containing the templates
if values:
for value in values: self.template_values[value] = values[value]
self.response.out.write(template.render(PATH+template_name, self.template_values, *args, **kwargs))
##Returns request as the name suggests
def logout_url(self):
return users.create_logout_url(self.request.url)
##Returns request as the name suggests
def request(self):
return request
##Returns openid login urls
def openid_providers(self):
#OPENID_POVIDERS is a list of dictionary
for p in OPENID_PROVIDERS:
p['login_url'] = users.create_login_url(self.request.get('next', '/') , p['name'], p['url'])
return OPENID_PROVIDERS
Everything is working fine except that I cannot pass some variables during initialization as self.request is not available. So for a workaround what I did is pass on whole self variable as a template variable.
Is there some other way to provide the template variables (request, logout_url etc) to the templates?
A much simpler solution than bgporter's is to do the common setup in the initialize method of webapp.RequestHandler. Here's an example from work, where we wanted to add a Django-like is_ajax method to the request object:
class BaseHandler(webapp.RequestHandler):
def initialize(self, request, response):
super(BaseHandler, self).initialize(request, response)
# Add a Django-like is_ajax() method to the request object
request.is_ajax = lambda: \
request.environ.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
This method is called to, uh, initialize each request handler with the current request and response objects, before the appropriate get or post (or whatever) methods are called.
I've solved that problem in my AppEngine code by using the Template Method Pattern
Basically, the base class looks like:
class MyBasePage(webapp.RequestHandler):
def __init__(self):
# common setup/init stuff here,
# omitted for this discussion
def Setup(self):
# request handling setup code needed in both GET/POST methods, like
# checking for user login, getting session cookies, etc.
# omitted for this discussion
def get(self, *args):
self.Setup()
# call the derived class' 'DoGet' method that actually has
# the logic inside it
self.DoGet(*args)
def post(self, *args):
self.Setup()
# call the derived class' 'DoPost' method
self.DoPost(*args)
def DoGet(self, *args):
''' derived classes override this method and
put all of their GET logic inside. Base class does nothing.'''
pass
def DoPost(self, *args):
''' derived classes override this method and
put all of their POST logic inside. Base class does nothing.'''
pass
...your derived classes then mostly just need to worry about the guts of those DoGet() and DoPost() methods.