Django Includes - are they evil? - django

A friend and developer I respect recently advised that I avoid using 'Includes' in django templates. The sum of their argument was that includes are 'evil'.
I am having trouble understanding the logic; My novice opinion is that they are a great way to organise chunks of reusable html, and instead of having to edit html in multiple locations I can simply edit it in one when changes must be made.
What do all you geniuses think? Please provide some Pro's and Con's of using includes in Django templates

It seems a slightly odd opinion. Includes are a perfectly valid part of the template language, have been so since day 1 and have never AFAIK been recommended against or deprecated.
Your friend might be trying to say that you should rely more on template inheritance (which is kind of an opposite include). That's true as far as it goes - most of the time it's better to compose your templates of blocks that override or extend ones defined in parent templates. But there's definitely a use-case for includes.
The only other reason he might say that would be because of the added filesystem hit of loading include templates from disk. In which case, he's definitely off the mark - again, the template inheritance model which definitely is recommended would have exactly the same hit; and both can be avoided by using the optional caching filesystem loader.

As mentioned by Daniel, includes are perfectly valid for the reasons he mentioned. As such it is difficult to give Pro's and Con's because it really depends on what you're trying to accomplish.
Generally it is best to define common elements of a website inside block tags in a base template and use template inheritance to change out the parts you need on each page. However, if you simply need to reuse a snippet of text in many places, an 'includes' would be perfect.
An important point to note is that includes cannot contain block tags as they are rendered by themselves without any knowledge of the parent page. To better understand this see the note from the template docs on includes or this (non-bug) bug report. If you find yourself needing this functionality, it may be worth considering if you should instead move the included file into a base template inside a block tag.

He might be saying you'd be better off writing custom tags. So instead of having:
{% for post in blog %}
{% include "blog.tmpl" %}
{% endfor %}
you should do:
{% for post in blog %}
{% formatPost post %}
{% endfor %}
The include method relies on the blog posting being in an object called 'post', whereas the custom tag method lets you format anything. For example if you had a page that compared two blog posts, you would send them as as 'post1' and 'post2' in the context and do:
<h1>John Said</h1>
{% formatPost post1 %}
<h1>And Fred Said</h1>
{% formatPost post2 %}
Much more reusable. With includes you'd have to rename each of post1 and post2 as 'post' and then include the template...

Related

Use Django templates to generate forms

I’m planning to use the Django templating system in a slightly uncommon way. I need an app that will let me easily create simple “fill in the gap”-style forms and I decided to use Django templates with custom tags to design the forms.
Here is a sketch of what I mean:
<p>
This is the <i>form</i>. Two plus two is {% gap four 4 vier %}.<br>
The best programming language is {% case_gap Python Haskell %}.
</p>
{% if all_correct %}
You are smart.
{% else %}
<input type="submit">
{% endif %}
The idea is that the *gap tags render a text input control, look into the context to see if the answer for them was sent, and if the answer is correct, mark the text inputs green.
The question is how to implement the all_correct logic. The simple solution is to add this variable to the context and then make each *gap tag update it based on its correct answer, and, I believe, this should work with my example. But what if I want to move the {% if all_correct %} code to the top of the template, where none of the gaps were rendered, and thus none of them have validated their answers yet?
Looks like I need some way to iterate over all the *gap tags before starting to render the template and [ask them to] validate the answers, but I don’t know the internals of the templating system well enough to implement this. Or there might be a completely different and better way.
I believe I figured how to do this after reading Chapter 9 of The Django Book.
Creating of a custom template tag involves defining of two things: how to compile the tag and how to render it. The compile-function should parse the tag data and return a Node—basically a thing that has a .render(self, context) method and some other data derived from the tag text.
The solution is to create FormNode—a subclass of Node that will also have a .validate(self, context) method. Then our custom tag will be compiled to a subclass of FormNode that implements validation logic.
The next thing to do is to create FormTemplate—a subclass of Template with a super-power: before starting to render individual nodes it will validate all the nodes by iterating over them and calling validate(context) on all the subclasses of FormNode and it will set the all_valid variable in the context.
Here is my proof-of-concept implementation: https://github.com/kirelagin/django-template-forms. I believe it works pretty well.
I used the ability to instantiate a custom template engine, which was added in Django 1.8. Overall, I had to dig a little deeper than one might expect and I always had this feeling that splitting of the templating API and the django engine (which is now just one of the available backends) wasn’t complete yet. I hope that Django 2.0 will bring us new cool stuff and all the hacks I had to add will vanish.

Subrequests in Django templates

I'm working on my first Django project and have my templates setup with a base that all the others extend. In that base I want to have some user-specific navigation which means loading some values from the database to build the contents of a drop down menu. However I don't want to have to do this inside each view. Coming from Symfony2/Twig I would normally do this using a sub-request where I tell the template to render a view and that will use it's own template. Using syntax like:
{% render 'Bundle:Controller:action' with {} %}
How would I accomplish this same thing with Django? I've read over the docs a couple of times but can't find any way to do this.
You have two approaches:
(better)
- add the code to base.html (the one you're always extending) and only override it when you need to.
or
(worse)
- in every template use {% include %} to include your menus.html template.
Update: re-reading your question: you could modify the request in context-processor so your base.html would then have this information.
Custom template tags are what you want.

How to structure a website in Django?

I have a simple (I hope so) question about the structure of a typical Django website. I have to restructure my site using some "Django-powered" pages mixed to other typical static pages.
I'd like to have a few templates and a lot of pages using these templates.
My question is:
What is the best way to provide different content for each page?
What I'm thinking right now is having different pages in my URL conf using the same templates and modifying the content within the View. But it's so unnatural to "hard-code" my content within the View, I suppose.
Is there a way to define content areas in my template and, for example, edit them within the Admin panel?
There must be better ways, I think.
Thank you!
Edit
Maybe Flatpages could help in my task. But does exist a way to add "content areas" tied to specific parts of the templates? I can fine only the main content area.
How are your "content areas" different than django's template blocks? You can define something like this in your layout file:
base.html
{% block overridable %}Default content{% endblock overridable %}
And in your templates, you extend it like this:
view.html
{% extends "base.html" %}
{% block overridable %} Overrided by view {% endblock overridable %}
You can use generic views, and I would heartily encourage you to. They're great. Check out the django docs for generic views. But as for different pages requiring a different template, yeah, that's how websites work.
Django is not "file-light" - it works by combining lots of small files. You're quite right to be averse to hard-coding HTML in your view controller - that's generally bad practice. You're going to have a template for each view, but really, how many views do you have? Even in a large application, the number of views that can't be handled by either a built-in or custom-made generic view is going to be pretty low.

How to conditionally skin an existing site (for partner branding)

I've got an existing Django site, with a largish variety of templates in use. We've agreed to offer a custom-skinned version of our site for use by one of our partners, who want the visual design to harmonize with their own website. This will be on a separate URL (which we can determine), using a subset of the functionality and data from our main site.
So my question is: what's the best way to add reskin functionality to my site, without duplicating a lot of code or templates?
As I see it, there are several components which need to work together:
URL: need to have a different set of URLs which points to the partner-branded version of the site, but which can contain all the standard path info the site needs to build pages.
Template 'extends': need to have the templates extend a different base, like {% extends 'partner.html' %} instead of {% extends 'base.html' %}
View logic: need to let the views know when this is the partner-branded version, so they can change the business logic appropriately
My idea so far is to put the partner site on a subdomain, then use a middleware to parse the domain name and add 'partner' and 'partner_template' variables to the request object. Thus, I can access request.partner inside my views, to handle business logic. Then, I have to edit all my templates to look like this:
{% extends request.partner_template|default:'base.html' %}
(According to this answer, 'extends' takes a variable just like any other template tag.)
Will this work properly? Is there a better way?
If you are using different settings.py for the different sites you can
specifiy different template loading directories. (Which may default to your unskinned pages.)
Personally I'm not convinced by having different business logic in the same view code, that smells like a hack to me - the same as extensive conditional compilation does in C.
So to sum up.
Use django.contrib.sites and different settings.py
Get a clear idea, how much this is a new app/website using the same data, or just different css/templates.

Is it safe to render user-created Django templates?

Is it safe to let users make their own Django templates with a set of pre-defined variables, and then render this template on the server? I would only pass a very limited set of parameters to render, all of which are strings. Templates would be something like:
hey, my name is {{name}}.
So, the question is, are there any django template tags that can be abused to get information that users are not supposed to get? I'm most worried about the {% url %} tag.
P.S.
I noticed this question after filling out the title, however, my question is slightly different. I will probably allow no HTML/javascript at all, use Textile/Markdown, or find a way to restrict HTML to a very basic set of tags.
There're three main risks:
Users modifying the data. For example, rendering {{ request.user.kill }} will trigger kill() call during value lookup. To prevent this, you should set kill.alters_data = True in your model code. All built-in model methods that modify data are already marked, so the risk is only associated with your own methods or ones provided by poorly-written 3rd party apps.
Users directly accessing data they should not see. When RequestContext is used (which is most of the time), there're many variables added to template rendering context. Add user-defined templates and you're getting quite dangerous mix, because user can view anything added by any context processor.
Users accessing data they should not see through relations. When you pass model instance to template, its relations could be travesred futher than you could expect: {{ current_user.corporate_account.owner.ssn }} Oops...
A good preventive measure would be carefully reviewing your model relations to make sure you're not exposing something sensitive.
Overall, I'd say it is safe as long as you are aware of risks above and render user-supplied strings separately from regular templates. And make sure you eplicitly forbid {% debug %}, {% include %}. {% ssi %} template tags, as they can give away quite sensitive information. Maybe you can play it safe and only allow variables and filters and forbid control tags altogether.
include and ssi looks too dangerous for my taste, especially ssi which uses absolute paths. My opinion is that this is too risky business.
Well, from a server-side perspective it's safe (probably, no one has ever audited it), however the users could obviously generate any Javascript they wanted to perform XSS attacks.
It's not safe, the templates documentation says:
The template system isn’t safe against untrusted template authors. For example, a site shouldn’t allow its users to provide their own templates, since template authors can do things like perform XSS attacks and access properties of template variables that may contain sensitive information.
It runs deeper than just XSS attacks, or accessing user's data, if you try to do it, you will most probably have some vulnerabilities and you won't be aware of them.