How to access the request in models.py, django - python

#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

Related

Pass request to django inherited classes

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.

Creating restricted pages in google app engine

I'm having trouble creating admin pages on my Python Google App Engine site. I think the answer should be pretty straightforward, but honestly, I've been trying to understand how classes inheriting from other classes, or using functions to wrap other functions, and I just can't seem to get a good understanding of it.
Basically, my site has two kinds of pages: the main page, and then some pages that allow the user to perform admin actions. The main page can be seen by anyone without signing in. The other pages are for admins. The only users with accounts are admins, so I've set up webapp2 sessions, and as long as
self.sessions.get('username')
returns something that's enough to be allowed access to the other pages.
Here are my handlers:
class BaseHandler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render(self, template, **kw):
self.response.out.write(render_str(template, **kw))
def dispatch(self):
# Get a session store for this request.
self.session_store = sessions.get_store(request=self.request)
try:
# Dispatch the request.
webapp2.RequestHandler.dispatch(self)
finally:
# Save all sessions.
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session(self):
# Returns a session using the default cookie key.
return self.session_store.get_session()
class MainHandler(BaseHandler):
def get(self):
animals = Animal.query().fetch(100)
self.render('index.html',animals=animals)
class AdminHandler(BaseHandler):
def get(self):
if self.session.get('username'):
self.render('admin.html')
else:
self.render('signin.html')
class ReorderHandler(BaseHandler):
def get(self):
self.render('reorder.html')
def post(self):
#Change order of item display
self.write('OK')
class DeleteHandler(BaseHandler):
def get(self):
self.render('delete.html')
def post(self):
#Delete entry from db
self.write('OK')
class AddHandler(BaseHandler):
def get(self):
self.render('add.html')
def post(self):
#add entry to db
self.write('OK')
class SigninHandler(BaseHandler):
def post(self):
#Check username and password
if valid:
self.session['username'] = username
self.redirect('/admin')
else:
self.write('Not valid')
The AdminHandler lays out the basic logic of what these Admin pages should do.
If someone is trying to access an admin pages, the handler should checks to see if user is signed in, and if so, allow access to the page. If not, it renders the sign-in page.
Reorder, Delete, and Add are all actions I want admins to be able to do, but there might be more in the future. I could add the AdminHandler logic to all the GETs and POSTs of those other handlers, but that is extremely repetitive and therefore I am sure that it is the wrong thing to do.
Looking for some guidance on how to get the logic of AdminHandler incorporated into all of the other Handlers that cover "administrative" tasks.
Update: Brent Washburne pointed me in the right direction enough to get the thing working, although I still don't feel like I understand what the decorator function actually does. Anyway, the code seems to be working, and now looks like this:
def require_user(old_func):
def new_function(self):
if not self.session.get('username'):
self.redirect('/signin')
old_func(self)
return new_function
class AdminHandler(BaseHandler):
#require_user
def get(self):
self.render('admin.html')
class AddHandler(BaseHandler):
#require_user
def get(self):
self.render('add.html')
#require_user
def post(self):
name = self.request.get('name')
qry = Animal.query(Animal.name == name).get()
if not qry:
new_animal = Animal(name=name)
new_animal.put()
self.write('OK')
And so on for all the other "admin" Handlers.
Here's a brute-force way to ensure a user is logged in for every page (except the login page), or it redirects them to the login page:
def dispatch(self):
# Get a session store for this request.
self.session_store = sessions.get_store(request=self.request)
if not self.session['username'] and self.request.get('path') != '/login':
return redirect('/login')
A better way is to add this code to the top of every get() and put() routine:
def get(self):
if not self.session['username']:
return redirect('/login')
An even better way is to turn that code into a decorator so all you need to add is one line:
#require_login
def get(self):
....

Keeping an object over the lifetime of a request in Flask

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()

Google App Engine, define a Preprocessing class

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.

Conditional Django Middleware (or how to exclude the Admin System)

I want to use some middleware I wrote across the whole of my site (large # of pages, so I chose not to use decorators as I wanted to use the code for all pages). Only issue is that I don't want to use the middleware for the admin code, and it seems to be active on them.
Is there any way I can configure the settings.py or urls.py perhaps, or maybe something in the code to prevent it from executing on pages in the admin system?
Any help much appreciated,
Cheers
Paul
The main reason I wanted to do this was down to using an XML parser in the middleware which was messing up non-XML downloads. I have put some additional code for detecting if the code is XML and not trying to parse anything that it shouldn't.
For other middleware where this wouldn't be convenient, I'll probably use the method piquadrat outlines above, or maybe just use a view decorator - Cheers piquadrat!
A general way would be (based on piquadrat's answer)
def process_request(self, request):
if request.path.startswith(reverse('admin:index')):
return None
# rest of method
This way if someone changes /admin/ to /django_admin/ you are still covered.
You could check the path in process_request (and any other process_*-methods in your middleware)
def process_request(self, request):
if request.path.startswith('/admin/'):
return None
# rest of method
def process_response(self, request, response):
if request.path.startswith('/admin/'):
return response
# rest of method
You don't need to muck around with paths.
If you want to exclude a single middleware from a view, you must first import that middleware and do:
from django.utils.decorators import decorator_from_middleware
from your.path.middlewares import MiddleWareYouWantToExclude
#decorator_from_middleware(MiddleWareYouWantToExclude)
def your_view(request):
....
If you want to exclude ALL middleware regardless of what they are/do, do this:
from django.conf import settings
from django.utils.module_loading import import_string
from django.utils.decorators import decorator_from_middleware
def your_view(request):
...
# loop over ALL the active middleware used by the app, import them
# and add them to the `decorator_from_middleware` decorator recursively
for m in [import_string(s) for s in settings.MIDDLEWARE]:
your_view = decorator_from_middleware(m)(your_view)
middleware functions are basically called for every request, including image src, api, form, ajax calls etc. somehow people reckon it is only called before and after view. This not only can cause performance concern, but also is hard to change.
I do not recommend path comparison unless using reverse, on the one hand, reference modification may create more trouble; on the other hand, if conditionals seems messy.
here I provide a solution for converting middleware to decorator, this method requires you to add decorator manually to all views. Fully optimised, you can make decisions which right middleware is for the right view
before I had:
class AjaxMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
def is_ajax(self):
return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
request.is_ajax = is_ajax.__get__(request)
response = self.get_response(request)
return response
class DeletionMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
from staff.models import Deletion
response = self.get_response(request)
Deletion.auto_clean_up()
return response
MIDDLEWARE = [
'common.middleware.DeletionMiddleware',
'common.middleware.AjaxMiddleware',
]
now I created a decorators.py:
from django.contrib.auth.models import User
class Shape:
#staticmethod
def before(request):
pass
#staticmethod
def after(request):
pass
# All default to call, pass in as excluder param to escape
# Part default not to call, pass in as includer param to execute
class All(Shape): pass
class Part(Shape): pass
class Mixins:
class Online(Part):
#staticmethod
def after(request):
if request.user.is_authenticated:
request.user.profile.visit()
class Deletion(All):
#staticmethod
def after(request):
from staff.models import Deletion
Deletion.auto_clean_up()
class Ajax(All):
#staticmethod
def before(request):
def is_ajax(self):
return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
request.is_ajax = is_ajax.__get__(request)
def common_dec(excluders=[], includers=[]):
def common(function):
# def wrapper_func(*args, **kwargs):
# return function(*args, **kwargs)
# return wrapper_func
"""
common view that returns a template
does not incldue images and cdn access
"""
def wrapper_func(request, *args, **kwargs):
# iterate all classes in Mixins
alls = All.__subclasses__()
parts = Part.__subclasses__()
list(map(lambda cls:cls.before(request) if cls.__name__ not in excluders else 0, alls))
list(map(lambda cls:cls.before(request) if cls.__name__ in includers else 0, parts))
response = function(request, *args, **kwargs)
list(map(lambda cls:cls.after(request) if cls.__name__ not in excluders else 0, alls))
list(map(lambda cls:cls.after(request) if cls.__name__ in includers else 0, parts))
return response
return wrapper_func
return common
def common_mix(excluders=[], includers=[]):
class CommonMixin:
def dispatch(self, request, *args, **kwargs):
alls = All.__subclasses__()
parts = Part.__subclasses__()
list(map(lambda cls:cls.before(request) if cls.__name__ not in excluders else 0, alls))
list(map(lambda cls:cls.before(request) if cls.__name__ in includers else 0, parts))
response = super().dispatch(request, *args, **kwargs)
list(map(lambda cls:cls.after(request) if cls.__name__ not in excluders else 0, alls))
list(map(lambda cls:cls.after(request) if cls.__name__ in includers else 0, parts))
return response
return CommonMixin
which I can do
# common_dec implement all Shape.All middleware
#common_dec()
def index(request):
return render(request, 'index.html')
# this will except Deletion middleware, and include Online middleware, and execute all Shape.All
#common_dec(['Deletion'], ['Online'])
def index(request):
return render(request, 'index.html')
for class based view:
# this will execute all Shape.All, and include Online which is a Shape.Part
class ArticleDetailView(common_mix(excluders=['Online']), LoginRequiredMixin, DetailView):
pass
I have give up middleware since it lacks flexibility, this method largely saves performance and is implementable for large scopes view definition, will not causing any bug.
if you want to add a middleware, simply add a class to Mixin inheriting Shape.All, then it will be called for all decorated view function and classes. if you have a new type of view function that needs a new middleware, define it as Part and include it in decorator .it is also extremely convenient to exclude some middleware in particular view.

Categories