Django prevent caching of included html fragment - django

I have a Django view which uses the decorator to enable caching:
#cache_page(24 * 60 * 60) # cache for 24 hours
def index(request):
# view code
this view corresponds to a template like so:
{% extends "base.html" %}
{% load i18n %}
{% block content %}
html code
{% endblock %}
the base.html:
{% load i18n %}
<!DOCTYPE html>
<html>
<head>
<div id="content">
{% block content %}
{% endblock %}
</div>
<!-- need to tun off caching here... -->
<div id="sidebar">
{% include "language_switcher.html" %}
{% include "login_box.html" %}
</div>
<!-- ...and then back on -->
</body>
</html>
In the side bar I have a couple of dynamic elements which should not be cached. How can I 'turn off' the caching for this part of the template (sidebar) only?
Any help much appreciated.

Check this app: https://github.com/codysoyland/django-phased and this blog post: http://www.holovaty.com/writing/django-two-phased-rendering/

I'm assuming you're aware of template fragment caching - I don't believe setting a lower value here will override a view-level cache set to a longer period, though. This of course would mean you'd have to cache different parts of your index.html separately, which is feasible but not likely what you want.
You might also look at the clearcache tag for template fragments implemented here.

You can't, really. When you cache the whole view, Django doesn't process it at all. It just returns the same response from the cache, which includes the fully formed HTML. You can add vary headers to the cache, but that won't help you unless there's something to vary on (logged in user, etc.). It won't help with just a basic block of changing content not tied to anything else.
Remove the view-level caching and manually cache things in the view that you want. Otherwise, you're out of luck.

Related

Django: how to set up the site name and show it at the end of all pages title

For example, there are 3 html templates with different titles:
<title>Page1</title>
<title>Page2</title>
<title>Page3</title>
How to append all the titles with the site name at the end using variable (or other ways)?:
<title>Page1 - {{Here is the configurable Site Name}}</title>
<title>Page2 - {{Here is the configurable Site Name}}</title>
<title>Page3 - {{Here is the configurable Site Name}}</title>
You normally do this by setting the site name in a base template that you then extend from your other templates.
Suppose you have this base.html template
<html>
<head>
<title>{% block page-title %}{% endblock %} - My Site</title>
</head>
...
You can then extend this template from your other pages:
{% extends "base.html" %}
{% block page-title %}My first page{% endblock %}
...
This solution is what is normally seen in many Django projects.
Now if you want to make the site name configurable, from your Django settings for example, you'll need a way to pass it along to your view for rendering. Since this is something you'll be doing for every view, it's better to do this in context processor so you don't have to do it manually.

Django nested templates

In trying to keep with DRY, I'm setting up my Django project HTML files now. I have successfully extracted most repeated information to my base.html page. On most (but not all) of my pages, my content is displayed within a general 'panel' which is basically just a container set-up with styling, but it's got a few div-tags to it so it looks a bit ugly and I'm having to type out the exact same code out several times on each page.
My idea was to extract this to a 'panel.html' then call it whenever I need it, for example some pages might just have one 'panel' whereas my dashboard (it's an administrative site) will have maybe 15+. So it seemed a better idea and cleaner to not have to type out all this code each time I need to set up a 'panel'.
My ideal page would look something like..
{% extends 'base.html' %}
{% block content %}
{% extends 'panel.html' %}
{% block panel_content %}
Panel content...
{% endblock panel_content %}
{% extends 'panel.html' %}
{% block panel_content %}
Second panel content
{% endblock panel_content %}
{% endblock content %}
I know I can't use extends multiple times but I'm using it just as an example for what it is I'm trying to achieve.
I am going to potentially have hundreds of these identical 'panels' across my site but each containing different content and it would be so much cleaner if I could just have one stored somewhere in a HTML file and call it however many times I need.
Is there a way to do this?
You can use include
{% include "panel.html" %}
I should mention that too many include statements create a performance issue.

Django how to dynamically add js and CSS in sub templates?

I am new to Django.
I have a basic template set up where I have base.html using {% block body %}{% endblock %} to include a sub template of index.html and test.html where they have {% extends 'base.html' %} at the top.
The base.html template includes Bootstrap. It is where the CSS and JS are included. index.html needs to include select2 but test.html does not.
I could use blocks here to solve my problem (adding CSS and JS block to base.html) but I see that as getting very messy very quickly.
Is there anyway I can use assets in Django to create a select2 asset and have that called in the sub template to register the needed JS and CSS with the parent template?
All I see is compression and numerous searches have, so far, come up empty.
It okay to add 2 more blocks in your base.html:
<some css>
{% block additional_css %}
{% endblock additional_css %}
...
<some js>
{% block additional_js %}
{% endblock additional_js %}
and the override them in any page extended from base.html:
{% extends "base.html" %}
{% block additional_css %}
<link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap-datetimepicker.min.css' %}">
{% endblock additional_css %}
...
{% block additional_js %}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.0/moment.min.js"></script>
<script type="text/javascript" src="{% static 'js/bootstrap-datetimepicker.min.js' %}"></script>
{% endblock additional_js %}
That is a good practice because in this case the scripts will load in the very end and if some of your added script require for example JQuery, you won't face any problems.
It doesn't make the code messy, it's flat and easy to explain. It's better to think how not to make JS messy, and as you pointed, there are several ways to do this, on of them is to compress all the JS.
There are a few options that I can think of
The first is the ugly way that involves an {% if include_my_js_please %} in the base.html that is ignored if the context variable isn't included and for obvious reasons, arguments would be had if this made its way into our production code
The second is the way that you say can get very messy but its the way we do it and works very well for us, we have an {% extended_head %} and {% extended_footer %} in the base.html and as you'd expect we use this sparingly when required. Although we are very careful about what is included into this.
The third way is to just include everything in the base.html and only worry about it when it actually becomes a problem (I can see both the pros and con's of this)
and the fourth and final way I can think of is to make use of the Forms Media class
Django allows you to associate different files – like stylesheets and scripts – with the forms and widgets that require those assets. For example, if you want to use a calendar to render DateFields, you can define a custom Calendar widget. This widget can then be associated with the CSS and JavaScript that is required to render the calendar. When the Calendar widget is used on a form, Django is able to identify the CSS and JavaScript files that are required, and provide the list of file names in a form suitable for easy inclusion on your Web page.
Obviously this doesn't work in all use cases

Best practice for Django components

Django provides a means of collecting assets into its Widget framework, and in turn using a form to present it, but how about doing this outside the forms framework?
For example, let's say I just want a simple, self-enclosed web component that requires two .js files, a CSS file, a template, and is backed by a view to generate some data. This isn't a "form" because it's not intended to collect input. Rather, assume it's, say, a customized scrollbar. I can't seem to find the right match for this usage pattern even though it seems common and straight-forward.
To do this now seems to mean adding the CSS to the top-level template; the JS to the template (or script tags arbitrarily in the included document); and then rendering the form as an include. But wouldn't it be easier to have something like:
class ScrollBar(...):
template_name = ...
class Assets:
...
and then rendering it via a templatetag, but with the ability for a context processor or other hook to extract the assets into their appropriate places in the page?
Something like:
index.html:
<html>
<head>
...
{% compressed_css %}
</head>
<body>
...
{% compressed_js %}
{% block content %}
{% endblock %}
</body>
scrollbar-using-page.html
{% extends "index" %}
{% block content %}
{% scrollbar args %}
{% endblock %}
with the end result being the scrollbar's template is rendered with the specified args, and its JS and CSS are merged into the compressed_css and compressed_js areas, respectively, above?
I think we get there almost 100% via this approach, without the compressed_js/compressed_css sections, which raises the question of whether then we just included these in all shared pages. (Alternatively, we could use nested/inherited blocks.)
Adam

Template Django application extending template django project

I am quite a beginner in django and I need some advices.
I am trying as much as possible to create reusable django applications that will be used in several different projects. But I don't know how to proceed with templates.
If I have an application managing user, I think the template allowing to add, remove or list a user shall be located in the application and not in the project. Templates project should define headers, footers and general organisation (correct me if I'm wrong).
However, if I want to use template inheritance I will extend project template in my application template :
{% extends "base.html" %}
{% block content %}
...
{% endblock %}
So in developping my reusable application I make the assumption that my project will have a template called base.html with a block content, and in my mind this information should not be located at application level, but in project level. In some projects I will want to display users in block content, but not necessarily in others. I could want to display user information in several places in the same page for example...
How do you developp your application template to bypass this limitation ?
Thanks in advance,
Bill
What you are describing is probably best solved with custom template tags, specifically inclusion tags.
I would do a basic html template containing a header and a footer, and many reusable templates extending the basic one, containing the different layouts I would need. I would also create reusable components (tiles, datagrids...).
For the templates :
base.html
<!doctype HTML>
<html>
<head>
....
</head>
<body>
{% block content %}
</body>
</html>
3_columns.html
{% extends "project/base.html" %}
{% block content %}
<div class="line">
<div class="column">{% block col1 %}</div>
<div class="column">{% block col2 %}</div>
<div class="column">{% block col3 %}</div>
</div>
{% endblock %}
2_lines.html
{% extends "project/base.html" %}
{% block content %}
<div class="line">{% block line1 %}</div>
<div class="line">{% block line2 %}</div>
{% endblock %}
A basic custom component :
templatetags/custom.py
import django
from django.template.defaulttags import register
#register.inclusion_tag('components/custom.html')
def custom(params):
context = {
'a': params['a'],
'b': params['b']
}
return context
templates/components/custom.html
<div class="custom">
<label>{{ a }}
<input name={{ b }}
</label>
</div>
django-admin.py collectstatic
Read docs
Files are searched by using the enabled finders. The default is to look in all locations defined in STATICFILES_DIRS and in the 'static' directory of apps specified by the INSTALLED_APPS setting.