Apply decorator to context processor - python

I'm using Fandjango for a Django Facebook Canvas app.
To use fandjango, you need to wrap all view functions with #facebook_authorization_required, which makes sure you're authorized, then gives you the variable request.facebook.user.
What I want is to make a context processor which defines a few more variables based on this, i.e., I want all my templates to be able to use fb_user as a shortcut for request.facebook.user.
The problem is, I don't know how to use the decorator on the context processor.
Any ideas how I can do this?

There's no need to wrap the context processor. If you've wrapped the view in the first place, then the request will already be annotated with the facebook.user attribute. Since the request is passed to the context processor anyway, you have access to that attribute.
You should probably do a quick check - if hasattr(request, 'facebook') - within the context processor, just to make sure it's being called from a wrapped view.

Related

What does this mean in the django documentation about class-based views?

A rookie here. As I am reading the django documentation, I came up with a note that I cannot fully understand.
It says:
Note
While your class is instantiated for each request dispatched to it, class attributes set through the as_view() entry point are configured only once at the time your URLs are imported.
Here is the link:
https://docs.djangoproject.com/en/2.2/topics/class-based-views/intro/
So which one is better? What advantage does each have? I've tried both and cannot experience any difference(Pretty sure that's because I've not considered enough)
If you are passing any values into the as_view() method that are likely to change after the server starts, for example some function call or database query whose return value could change after some users use the website, it will be evaluated only once, while the urls are loaded.
Let's say you are passing in the current time like:
path('about/', GreetingView.as_view(greeting=timezone.now())),
That note simply says that the value of the attribute 'greeting' for GreetingView will stay the same for all requests even if the server runs for a month, since timezone.now() is called only once.
Such arguments are good for reusing a View class with minimal changes. It depends completely on your use case.
For example:
path('add-car/', AddView.as_view(form=AddCarForm)),
path('add-bus/', AddView.as_view(form=AddBusForm)),

Initializing a class at Django startup and then referring to it in views

I am trying to do some pre-processing at Django startup (I put a startup script that runs once in urls.py) and then use the created instance of an object in my views. How would I go about doing that?
Try to use the singleton design pattern.
You can use a Context Processor to add it to your template context.
If you want it in the View, rather than the Template, then you can either have a base View class that has this, or just import the reference into the module your view is in (and access it directly).
Be aware that each django thread may have a different copy of the object in memory, so this should really only be used for read-only access. If you make changes to it, you are likely to find yourself in a world of hurt.

Django: How do I update a model after a view has been rendered?

I have a view that displays a list of models. Some of the properties of some of the models need to be updated after the view has been rendered: that is, the user is expected to see the original, unchanged values on first visit and the updated values on successive visits (or upon page reload).
I thought I could achieve this with class-based generic views. The official documentation hints at "doing some extra work before or after calling the generic view" (emphasis mine), but all examples given affect the models before it is displayed.
I looked into signals, but to no avail.
Spawning an asynchronous task is an option, but, since all I need to do is update a field in a few models (likely one or none) and save them, it seems overkill for the task at hand.
One could use an ajax request to trigger the update, or a custom template tag to display the relevant fields and update them thereafter. I dislike both, as they move application logic into the view layer. The ajax technique also adds the overhead of a second request.
Yet, I seem to have no other choices, or do I? Is there a more practical technique for plugging into the generic view or the request and execute extra logic after the template has been rendered?
There's no need for anything clever here. Rendering a template doesn't need to be the end of the view - that only comes when you actually return that as a response. They don't have to be in the same step.
So :
def my_view(request, params):
#...do something...
response = render_to_response('my_template.html', {'foo': bar})
# ...do something after rendering...
return response
Now, if you need to do this in a lot of views, you might want to do it in a decorator:
def my_decorator(view):
def my_func(request, params):
response = view(request, params)
#...do something after rendering...
return response
return my_func
now you can decorate your views with #my_decorator and the action will be performed after rendering.
... or, it just occurred to me, if you want to do it in every view, you could do it in a middleware (just define the process-response method).
Edit after comment Class-based generic views use the new TemplateResponse class. You can add tasks that happen after the template is actually rendered with a post-render callback.
Catch the return value from the view or function, do some processing, then kick it up the stack.
def foo(*args):
ret = bar(*args)
do_something()
return ret
Could you grab two copies of the object, modifying and saving one while passing the other (unmodified and outdated) one to the view?
I haven't used class-based generic views yet, so I can't give you a specific example.
Django also comes with a built-in signal request_finished, that is sent AFTER django finished processing the request.
If your project already use celery, you could create a task to update the model and
and call
your_task.delay()
You could use the countdown argument to specify an elapsed before launching the task.
If you are not using celery chances are that you will in the future :)

Django: request object to template context transparancy

I want to include an initialized data structure in my request object, making it accessible in the context object from my templates. What I'm doing right now is passing it manually and tiresome within all my views:
render_to_response(...., ( {'menu': RequestContext(request)}))
The request object contains the key, value pair which is injected using a custom context processor. While this works, I had hoped there was a more generic way of passing selected parts of the request object to the template context. I've tried passing it by generic views, but as it turns out the request object isn't instantiated when parsing the urlpatterns list.
To accomplish this, you will probably have to create your own middleware. That way, you have full control of the request, both before and after the view function.
Middleware is a very powerful concept, and not as hard to implement as it could seem, but don’t overdo it – it makes it hard to follow the program flow.
I don't necessarily understand your question well enough.
Either you are complaining having to include the RequestContext in all views, in which case you need to write a wrapper that passes RequestContext for you. But you will still have to pass to it the request. If you don't want to pass that too, you may have to create your own middleware as mikl suggests.
Or, you are complaining about having to pass a lot of menu items, in each and every view. Which is wrong way to do it, you need to define a template context processor that ensures these are present in the template by default.

Rendering common session information in every view

I'd like to output some information that depends on session data in Django. Let's take a "Login" / "Logged in as | Logout" fragment for example. It depends on my request.session['user'].
Of course I can put a user object in the context every time I render a page and then switch on {% if user %}, but that seems to break DRY idea - I would have to add user to every context in every view.
How can I extract a fragment like that and make it more common?
Use template inheritance to derive all of your templates from a common base that suitably uses the common parts of the context, and make all your contexts with a factory function that ensures the insertion in them of those common parts.
Are you trying to make certain areas of your site only accessible when logged on? Or certain areas of a particular page?
If you want to block off access to a whole URL you can use the #login_required decorator in your functions in your view to block certain access. Also, you can use includes to keep the common parts of your site that require user login in a separate html that gets included, that way you're only writing your if statements once.
You may want to use a context processor that includes logic and place it into a variable you can use in any of your pages without adding it to each call.
See more info at How to pass common dictionary data to every page in django

Categories

Resources