I have subclassed django-haystack's FacetedSearchView, and want to have an action take place when a specific GET parameter is present in the view's URL. I know exactly how to do this if I had a function-based view, but am at a complete loss when using a subclass of a subclass.
The request variable should be available somehow. I assume I need to call it up from some kind of super() call, maybe in an __init__() override? I've tried the following:
def __init__(self, *args, **kwargs):
super(MySearch, self).__init__(*args, **kwargs)
if self.request.GET.get("date_facet", ""):
do_something()
But it tells me that the returned request object is None, though by the URL it clearly shouldn't be.
Any thoughts?
Turns out, the request variable is accessible, it just has to be through self, which means you can only access it through a function common to the parent class. __init__ wasn't working, because request isn't defined until later in the parent class. To get things to work I ended up overwriting the get_results() class (originally just return self.form.search()), in a way similar to the following:
class Foo(ParentClass):
def get_results(self):
if 'date_facet' in self.request.GET:
year = int(self.request.GET['date_facet'])
return self.form.search().filter(some_filter_function)
return self.form.search()
Related
I was wondering if I could get any insight on this.
So far, I have this class:
class MaterialTaggingListView(ServerSideDatatableView):
def get_queryset(self):
vLatestUpdateDate = ScTaggingLargeTableIp.objects.values('update_date').order_by('-update_date')[:1]
request = self.request
if 'selectedcountries' not in request.session:
vSelectedCountries = ['CN']
else:
vSelectedCountries = request.session['selectedcountries']
vSelectedPlants =request.session['selectedplants']
vSelectedValClass = request.session['selectedvalclass']
vSelectedCoCode = request.session['selectedcocode']
columns = request.session['selectedtags']
return ScTaggingLargeTableIp.objects.filter(update_date = vLatestUpdateDate,plant_country__in=(vSelectedCountries), plant__in=(vSelectedPlants), valclass__in=(vSelectedValClass), company_code__in=(vSelectedCoCode))
def set_columns(self):
request = self.request
columns = request.session['selectedtags']
return columns
columns = set_columns()
With this code above, I got the error: missing 1 required positional argument: 'self'
Can anyone tell me if what I'm trying to do is possible and how I could resolve the error.
Usually, you need to initialize class attributes in __init__ method for this to work, because you cannot set the attribute to the object that has not been created yet.
But since you are using self.request object in the set_columns method, you need to override the setup method in which request object is initialized:
class MaterialTaggingListView(ServerSideDatatableView):
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.columns = self.set_columns()
No, you can't do that. You need to create an instance of a class to call non-class methods on it. What you can do - is either not set columns as a class-level variable, or make set_columns a classmethod, but in that case it won't be able to receive request in it (Django will create an instance of your view before processing request).
If you want to persist columns value between requests - store it in database or in cache.
I have code like this in my pyramid project:
class SomeViews(object):
#view_config(...)
def view_a(request):
return {...}
#view_config(...)
def view_b(request):
return {...}
I would like to decorate the view methods to modify the returned dictionary. It's possible to apply an decorator to a view, if it's the first one before view_config. Otherwise Pyramid is still using the original function, due to the nature of Venusian.
Because I would apply the same decorator to all methods in a class, I would prefer to use a class decorator. So instead of doing
#view_config(...)
#my_decorator("some_meta_info")
def view_b(request):
return {...}
for each method, I would like to do
#my_decorator("some_meta_info")
class SomeViews(object):
...
But because the class decorator is executed after the view_config calls, again it does not work with Venusian. I had a look at the view_defaults implementation, to get a hint how to solve my problem, but I did not figured out how it works.
Any hint how to do that? What I want to do, is just to modify the result dictionary of a set of view methods. I also thought about using the BeforeRender event, but I found no way to inject the required meta data in a way that I can access it in the event handler. Using decorators would anyway be the more natural and pythonic way in my opinion.
import functools
def my_decorator(value):
def _dec(f):
#functools.wraps(f)
def wrapper(context, request):
print 'hey look!', value
return f(context, request)
return wrapper
return _dec
#view_defaults(decorator=my_decorator('some meta info'))
class SomeViews(object):
def __init__(self, request):
self.request = request
#view_config(..., renderer='string')
def view_a(self):
return 'foo'
Think of view_defaults as default options passed to every view_config on the class. If you add a decorator to the view_config though, the defaults are overridden and your default decorator would be dropped.
I am working on a class based generic view that takes a model name as an argument and processes that model name to get some more parameters. I had it working fine when I hardcoded the model name into an entry in the URLconf:
url(r'^generic/', ResultCreateView.as_view(model = 'SomeTask'))
Snippets of the class based view:
class ResultCreateView(CreateView):
model = None #this is here, expecting to be overwritten, because otherwise I get an error saying I can't pass in the 'model' kwarg above because 'model' is not already an attribute of the class
def __init__(self,*args, **kwargs):
self.model = get_model_object_from_modelname(kwargs['model'])
self.form_class = my_custom_function_to_generate_a_formclass(self.model)
self.template_name = self.model.template #template_name is an attribute I set on the model class
return super(ResultCreateView,self).__init__(*args, **kwargs)
When I tried to switch to passing the model parameter in via the url, i.e.:
url(r'^tasks/(?P<model>\w+)$', ResultCreateView.as_view())
my custom init method no longer works. I get:
ResultCreateView is missing a queryset. Define ResultCreateView.model, ResultCreateView.queryset, or override ResultCreateView.get_queryset()
I can't figure out where/when the 'model' argument gets passed in from the URL pattern to the view class. Ideally, I would like to be able to make this view work in either case (hardcoded parameter in URLconf or parameter from URL pattern) but I don't know where to put the code that does the processing so that it happens at the right time. Where is the right place to put that code, or is there another approach I should be using?
EDIT: (Additional complication: I need to decorate the view with a decorator that takes 'model' as an argument.)
Those parameters will be passed to the actual request handler methods, not to the __init__ method of the view. so, in case of a GET request:
class ResultCreateView(CreateView):
model = None
def get(self, request, model_name):
self.model = get_model_object_from_modelname(model_name)
self.form_class = my_custom_function_to_generate_a_formclass(self.model)
self.template_name = self.model.template #template_name is an attribute I set on the model class
return super(ResultCreateView,self).get(request, model_name)
How can I create initialization code?
When I put the __init__ constructor always tell me that parameters are wrong.
Also please someone gave a example also using __new__ and one using super() and why should we use or not use them.
import webapp2
class MainHandler( webapp2.RequestHandler ):
def __init__( self ):
#initialization code/vars
x = 1
def get( self ):
#code for get here
self.response.write( x+1 )
def post( self ):
#code for post here
self.response.write( x+2 )
app = webapp2.WSGIApplication ( [ ('/', MainHandler) ], debug=True )
Finally got it...
The problem is that overriding "webapp2.RequestHandler" requires special special handling
from the webapp2 manual:
If you want to override the webapp2.RequestHandler.init() method, you must call
webapp2.RequestHandler.initialize() at the beginning of the method. It’ll set the current request,
response and appobjectsasattributesofthehandler.
Example:
class MyHandler(webapp2.RequestHandler):
def __init__(self, request, response):
# Set self.request, self.response and self.app.
self.initialize(request, response)
# ... add your custom initializations here ...
# ...
...and that's it...
now works as expected
;-)
If you aren't passing any arguments or including any of your own code in the __init__ method, there's usually no need to even create one. You'll just use webapp2.RequestHandler's __init__ method.
If you do need to make one, you still have to call webapp2.RequestHandler.__init__:
class theHandler(webapp2.RequestHandler):
def __init__(self, your_arg, *args, **kwargs):
super(theHandler, self).__init__(*args, **kwargs)
self.your_arg = your_arg
You need to have a self variable in all the functions within your class. You need to include this variable for the function to work within your class.
A good explanation to the need of the self variable in each function within a class can be found here.
I'm new to python and GAE and I thought python will act as any other OO language, but apparently not. How does __init__(self): function gives me different results in the following code?
class BaseHandler(webapp.RequestHandler):
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
user = User.get_by_key_name(cookie["uid"])
return self._current_user
class SubmitHandler(BaseHandler):
template_values = dict(facebook_app_id=FACEBOOK_APP_ID)
def __init__(self):
#throws error : AttributeError: 'SubmitHandler' object has no attribute 'request'
self.template_values['current_user'] = self.current_user
def get(self):
#this one function is error free
self.template_values['current_user'] = self.current_user
How do I access the class' parent property?
If you look at your SubmitHandler class you'll notice that it indeed does not have a request attribute -- at least, none you set, and none you give the parent class a chance to set. Perhaps what you need to do is call the parentclass __init__ method before you try to access self.current_user.
As a side note, you should realize that the template_values dict you define inside the SubmitHandler class there is a class attribute, and thus shared between all instances of the class. Since you assign it something instance-specific in your __init__, you probably mean for it to be an instance attribute instead. Assign it to self.template_values in your __init__ method.
There's nothing particularly different about Python's object inheritance.
By defining __init__, you have told Python that this is all that needs to be done to initialize the object. You're therefore denying it the chance to run the superclass's initialization code. You need to call super:
def __init__(self, *args, **kwargs):
super(SubmitHandler, self).__init__(*args, **kwargs)
self.template_values['current_user'] = self.current_user
This might however not solve your problem - you're failing to take into account the possibility that self.request is initialized at another point in the program, which is why it works by the time get is called.
self.request and self.response are not set by the class constructor in webapp. They're set later, when the framework calls the handler's initialize method. You can override this, just make sure you call the parent class's initialize before doing anything else.