When should I use {{attributes}} in twig opposed to hardcoding attributes? - templates

I was reading up on template development in Drupal. ( https://www.drupal.org/docs/8/theming-drupal-8/using-attributes-in-templates )
Drupal recommends creating an attributes object with create_attribute() and use the object that it creates to declare attributes to a html element. E.g.:
<div{{ create_attribute({'class': ['region', 'region--header']}) }}>
{{ content }}
</div>
Where I would usually just use:
<div class='region region--header'>
{{ content }}
</div>
I can imagine that this could be useful if you need to add attributes using some conditional logic. But I wouldn't want too much logic in a template.
I probably missed something essential here. Can someone clarify what the advantages of using create_attribute() are over hardcoding classes? When should I use the create_atribute() approach? What is a common scenario where the create_attribute() comes in handy?

IMHO there is no benefit of create_attribute() in your example, because attributes values are still hardcoded within create_attribute() function.
It is way more useful if attributes are hold in a variable that can be manipulated in (extended) templates with functions like addClass, removeClass, setAttribute,... For example we define attributes array (in twig or in processors) for given html element and you would simply render attributes with <div {{ create_attribute(attributes_for_this_div) }}></div>.
In Drupal core or in commonly used modules, I did not find single example of create_attribute() with hardcorded attributes.

Related

How to make dict always available to a particular template with Django/Jinja2?

I have a template (using jinja2) that is used in lots of views (via {% include %} statements). The template will always require (amongst other data that changes, and will be passed in via the context) a dict, that is a constant. It would be cumbersome to add the dict to the context in every view that will potentially use the template.
I could add the dict as a global variable in the jinja2 env.globals, but that doesn’t seem like a particularly good idea either. It is only needed in one template in one app, not the entire project.
The Jinja2 documentation mentions template globals specific to a particular template, but I can’t figure out how to implement this with Django.
Any help appreciated, thanks :)
EDIT: Some additional context.
The template provides some information to be used in lots of other html documents (via the include tag). The positions of the lines and polygons are the same, but the colours are different. I don’t particularly want to hard-code all of the x1=”20” x2=”30” etc, so it would be useful to have all of this stored in a dict, and do something like the following:
{# Template to be included #}
<svg class="a" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="none">
{% for i in range(10) %}
<line {{dict_always_available[i]}} class="{{info_passed_in_context[i]}}"></line>
{% endfor %}
</svg>
I don't want to have to pass dict_always_available into the context in every view that will potentially (but not necessarily) need it.

How to call a variable function with parameter in django template?

I want to achieve something like this within a Django template.
{{ variable.function(parameter) }}
Where variable is a variable passed through a context to a template, in this case, an instance of a model.
I have tried different methods, but no one seems to work.
This is not possible in Django templates: they are crippled on purpose in order to prevent template designers from shooting themselves in the foot. The reasoning is that the only logic in templates should be presentation logic and all business logic should be kept in the view. Some people thinks it is fair enough and some think it is a bit condescending (those dumb template designers are not smart enough to use functions and methods safely).
I can think of 3 choices:
use jinja2 instead.
write a custom template filter.
keep all the logic in the view where Django designers think you are supposed to keep it.
I will not explain how to use Jinja2 because it is already explained in the docs and because the example in the question works verbatim if you switch to it instead of native Django templates. This simply works in Jinja2:
{{ variable.function(parameter) }}
Now the template filter solution: first you must follow a code layout convention. The filter itself would be something like this:
# at your_tag_library.py
#register.filter(name='call_with')
def apply_callable(callable, arg):
return callable(arg)
Then in the template you can do:
{% load your_tag_library %}
{{ variable.function|call_with:parameter }}
Of course the last option is the one from Daniel's answer - precompute the value in the view and just display the result in the template:
context['result'] = variable.function(parameter)
And in your template you just need {{ result }}.
There is no way to do this.
You can create another variable and pass it through the context so you could use it.
Like:
context['result'] = variable.function(parameter)
In your view.
And in your template:
{{ result }}

TableBlock how to specify table CSS classes

I am struggling to add CSS classes to Wagtail StreamField & TableBlock (http://docs.wagtail.io/en/v1.8.1/reference/contrib/table_block.html).
Is the way to go to define a filter and use something like:
{{ child|className:"table table-bordered" }}
where className is my custom filter?
No, this isn't currently possible with the standard rendering of a TableBlock - the template used internally to render the block has hard-coded <table> / <tr> / <td> tags with no class attributes. However, you could specify a custom template in your TableBlock declaration, which would give you full control over the HTML:
StreamField([
# ...
('table', TableBlock(template='/path/to/custom/template.html')),
# ...
])
I think it's a good idea. Last time I needed to do something similar I found this blogpost which gives you a practically copy-and-paste solution to your problem. Django templatetags might have changed since then, but not by much.
EDIT: From the comments, this seems to be more modular.

String manipulation in Django templates

Imagine the context variable {{ url }} outputs www.example.com/<uuid-string> where <uuid-string> is different every time, whereas the former part of the URL stays the same.
Can one change the output of {{ url }} to instead www.forexample.com/<uuid-string>, via solely manipulating the string in the template and without involving views.py (which I know is the better way to do it, but that's not the question).
An illustrative example would be great.
read about filters and templatetags - they are a methods that allows you to perform some actions on variables in templates.
You can also create your own tags and filters that allow you to perform action non-built into Django template language
Simple example of such filter:
#in templatetags.py
#register.filter(name='duplicate')
def duplicate(value):
return value*2
#in your template
<p> {{ url|duplicate }} </p>
You can find more examples here. Also there you will find tutorial how to use and create them

Does django support separating your templates into parts?

I would like to create separate templates for each part of the page like Navigation, Side bar, Login panel, etc. Django seems to use inheritance rather than composition. I was wondering if there is any support for separating templates out into parts and passing in template specific models to each template. I'm thinking of something like:
values = {
'navbar_data' = ...
'sidebar_data' = ...
}
{{ template.render('navbar', navbar_data) }}
{{ template.render('sidebar', sidebar_data) }}
There are many good ways to do this.
You can use the builtin templatetage include for this. This template tag allows you to to use and reuse specific fragments of a template. This is usually most useful for mini templates that say represent a single model and will be used throughout the site. This can be especially useful if you combine it with the with templatetag to allow you to craft the context used in the included template
Alternatively just simply using block may give you the feel you're looking for
Finally you can use custom inclusion templatetags (https://docs.djangoproject.com/en/1.4/howto/custom-template-tags/#inclusion-tags) to give you an even deeper level of control. These will allow you to render a subtemplate with a completely custom context.
That is what templatetags are for. You define a tag in a file called myapp/templatetags/mytags.py, then in your template do this
{% load mytags %}
{% navbar %} {% sidebar %}
The official documentation has plenty of information about this.