I'm using Flask + Flask-Classy with jinja2 templates, and I want to inject some data into my templates for all requests in that view (eg, index, get, etc) without having to return it manually on each request.
Right now, if I use #app.context_processor to inject data, even if its defined as a class method inside the view, it gets run and injected for every single view/request (if I go to /signup (SignupView), I get data from /account (AccountView))
Is there any way to do this? Something like
class FooView(FlaskView):
def inject_data(self):
return dict(bar=123)
It looks like there's no way to do it with FlaskView, so in the end I just created another layer of blueprints for each subsection. Not ideal but it works.
Related
I generate URLs with a jinja2 template_filter using Flask:
#app.template_filter()
def generate_stuff(url):
return do_stuff(url)
This template_filter is only executed once per URL. If a user reloads the page I want Flask to run this function, again. How do I do this?
PS: I am new to Flask. If there is a better way to achieve the same I am also interested, of course :)
Template filters are the wrong thing to use here, those are for adding extra functions you can use against variables in templates. You're probably looking for context processors. You can use request.url to get the url, or there are other path properties on request as well if that's not what you want.
#app.context_processor
def inject_user():
return {
'my_stuff': do_stuff(request.url)
}
When using jinja2, base "skeleton" template are often extended by many other templates.
One of my base templates require certain variables in the context, and everywhere I use this base template I have to duplicate the setting up procedure.
For example, I may need to read some category names from DB and render them as a list in the header, now I have to write this query everywhere I use the base template.
What are some good way to avoid duplicating these kind of code when using jinja2?
You can add context processors to your app or blueprint. These inject extra values into the Jinja context. These aren't part of any view, but will run in the request context so you have access to everything you normally would in a view.
#app.context_processor
def base_context():
return {
'author': 'davidism',
'last_update': interesting_function()
'headers': db.query(MyModel.category).distinct().all()
}
Processors added on a blueprint are only available to templates rendered from a view on that blueprint.
Context passed to the render_template functions will override these default context values (if they have the same key).
One way I can think of is to use a decorator that provides extra context variables to each view's result.
You can use macros on Jinja2 or custom Filters:
Macros:
http://jinja.pocoo.org/docs/dev/templates/#macros
you can register your custom filters with decorators like this:
https://github.com/dpgaspar/Flask-AppBuilder/blob/master/flask_appbuilder/filters.py
I have a parent template that I'm using in many parts of the site, called base.html. This template holds a lot of functional components, such as buttons that trigger different forms (inside modal windows) allowing users to upload different kinds of content, etc. I want users to be able to click these buttons from almost any part of the site (from all the templates that inherit from base.html).
I've written a view that handles the main page of the site, HomeView (it renders homepage.html, which inherits from base.html). I've written a bunch of functionality into this view, which handles all the uploads.
Since many templates are going to inherit from base.html, and therefore have all that same functionality, do I have to copy-and-paste the hundreds of lines of code from the HomeView into the views that render all the other pages??
There's got to be a better way, right?
How do I make sure that the functionality in a parent base template holds true for all views which call child templates that inherit from this base template?
you can put all the lines of code from HomeView in a separate function let be func
and have func return a dictionary containing all context variables needed
and call it whenever needed so your HomeView would look like this:
def HomeView(request):
dict = func(request)
... # rest of code that is not common with other views
and your func would look like:
def func(request):
#all repeated code
#put all needed variables in a dictionary and return it
dict = {'var1': 4, 'var2': "a String" ...}
return dict
I believe separating out your upload related functionality into separate views will be better way to go about it. That way all your templates (inheriting from base.html) will refer to appropriate view for uploads.
You can use HTTP_REFERER header to redirect to appropriate page from the upload views.
You can render many templates in just one view by requiring unique value in each or use request session.
Use TemplateResponse instead of HttpResponse in home_view. This way you will be able to update context and switch template on the response.
Call home_view inside other views like this:
from django.template.response import TemplateResponse
def other_view( request ):
#produce other_context
t = home_view( request )
t.context.update( other_context )
t.template = 'other_template.html'
return t
Load the functionality part with ajax on your base.html.
That way you have a view_method that deals exclusively with those funcionalities.
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 :)
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