A little question to jinja2 templating:
I want to create a reusable template to include and then overwrite blocks. Macros do not let me write junks of HTML easily as parameters do they? Say I want to reuse an include several times and am using BIG junks of HTML in blocks that I want to dynamically assign
how would I do it?
certainly not with macros I guess, or am I wrong?
{% render_foo('bar',2) %} is fine
{% render_foo('<table><tr><th>something</th><th>somethingelse</th></tr><tbody><tr>....etc') %} is not fine any more is it
"what do you really want to do?"
yes, what I told you, I have a way I create containers for my data. The container is ALWAYS the same. The content is completely different on each usage. Once a table. Once a bootstrap component. Once a form.
The surrounding elements are always the same
to reproduce the simple error this is what I did:
{% include 'full_section.html' %}
{% block fullsection %} <table><tr><th>something</th><th>somethingelse</th></tr><tbody><tr>....etc{% endblock %}
{% include 'full_section.html' %}
{% block fullsection %} <form>//some cool LONG big form </form>{% endblock %}
full_section.html contents just for completeness, it is a lot more complex in reality
<div class="my_cool_full_section">
{% block full_section %}{% endblock %}
</div>
TemplateAssertionError: block 'fullsection' defined twice
I found the answer well hidden in the jinja2 docs
http://jinja.pocoo.org/docs/2.9/templates/#block-assignments
so you use a macro and a block assignment e.g. like this:
{% set section_content %}
<table><tr><td>etc</td> <td>etc</td> <td>etc</td></tr></table>
<table><tr><td>etc</td> <td>etc</td> <td>etc</td></tr></table>
<table><tr><td>etc</td> <td>etc</td> <td>etc</td></tr></table>
{% endset %}
{{ render_full_size_section(section_content) }}
{% set section_content %}
aaaaaaaaaaa
{% endset %}
{{ render_full_size_section(section_content) }}
wonder what they were doing pre 2.8... dark dark middle age
then in the macro:
{% macro render_full_size_section(content) %}
<div class="mycoolsection">
{{ content | safe }}
</div>
{% endmacro %}
Related
I have a for loop that contains an include tag like the following:
{% for thing in things %}
{% block example %}
{% include 'myapp/example.html' with thing=thing %}
{% endblock %}
{% endfor %}
I expected that the html in example.html would get rendered with each thing within things but it only gets rendered with the first thing object. Is there a way to pass each of the thing objects within things to example.html?
Your code is supposed to work, even with the {% block %} tags, as long as you do not redefine them somewhere else. Maybe the problem is on the things or myapp/example.html side?
Note: if you refer to thing with the same identifier in your child template, you don't need the with thing=thing part - for exemple, {{ thing }} will be directly avalaible in your child template.
Something you might want to try:
{% for thing in things %}
{% include 'myapp/example.html' %}
{{ thing }}
{% endfor %}
I have a list of strings that I will process and for brevity sake I am writing them as spans here.
I want some html to go inside a div, so,
<div class="something">
<span>something1</span>
<span>something2</span>
<span>something3</span>
...
</div>
And some other outside (depending on some condition)
<span>something-else1</span>
<span>something-else2</span>
<span>something-else3</span>
...
So the condition comes from something in the list. Is there any way so I can stop the control at a macro caller so I can have the same macro be called again so it would append the next span in the same place?
So something like
{% macro render_inside_div %}
<div class="something">
{{ caller() }} <-- I want to render multiple spans in within the same div
</div>
{% endmacro %}
EDIT:
Yes, of course that would work and that is (sort of) how I got it to work anyways. But I was looking for a 'cleaner' and DRY solution. So basically I would just iterate the list once and the way it would work would be something like this:
{% for row in my_list %}
{% if row.condition_for_div %}
{% call render_in_div %} {# Look before to see the macro I've written above #}
{{ do_something(row.data) }}
{% endcall %}
{% else %}
{{ do_something(row.data) }}
{% endif %}
{% endfor %}
so in this render_in_div I want to hand control to the caller() block many times, so the control (for that "context") would remain there until I say to get out (in some way like a generator?)
Just learning Django, and I'm trying to create a situation where when a template has layouts it'll list them, but if it doesn't it won't and will instead state that there are none.
I got an error message when I used only a "for layout..." statement on templates that had no layouts.
I figured things out to the point that I created an "if" statement to first check and see if the pages had layouts, and if not, an "else" statement to say that there are none.
The end result, though, is that the "for" seems to be completely ignored, and the "else" condition is applied on all pages -- whether or not they have associated layouts.
Code:
{% block header %}
<h1>The name of this template? It's {{ boilerplate.name }}.</h1>
{% endblock %}
{% block content %}
<p> </p>
<p>{{ boilerplate.content }}</p>
{% if layout in boilerplate.layouts %}
{% for layout in boilerplate.layouts.all %}
<p>{{ layout.user }} -- {{ layout.name }} ({{ layout.file.size }})
{% endfor %}
{% else %}
<p>There are no layouts for this template.</p>
{% endif %}
{% endblock %}
There's obviously something I'm missing. Possibly something very simple. What am I dong wrong?
Your {% if layout in boilerplate.layouts %} is what's wrong, but there's an easier way to achieve this than using an additional if tag.
As the documentation shows, you can use an optional empty tag to handle situations when you have no layouts. Rewriting your example code:
{% for layout in boilerplate.layouts.all %}
<p>{{ layout.user }} -- {{ layout.name }} ({{ layout.file.size }})
{% empty %}
<p>There are no layouts for this template.</p>
{% endfor %}
https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#for-empty
Look at this tag
To answer the subject of your question, yes, of course you can. My guess from the way you describe your problem is that there may be an issue with how you look for the layout in boilerplate.layouts.
boilerplate.layouts looks like it's a relational field. Thus, doing an in check on that alone may not be sufficient. In cases like this, I would recommend playing with this code in the shell, or in the view and seeing the result there, as it will greatly help debugging.
My simple guess is you need to do layout in boilerplate.layouts.all, but I am not familiar enough with your model, so wild guess :)
I am currently working on a symfony2 application and am using embedded controllers. My embedded controllers are like widgets which should encapsulate its own set of functionality and can be embedded anywhere and still be expected to function.
I have a controller called users online. The view it generates is simple, just a list of online users. But, I would like to add some javascript to that view so that I can use ajax to retrieve information for a user that's clicked on.
The controller basically returns a view:
return $this->render('AppBundle:Users:usersOnline.html.twig', array('somedata' => $data);
Here's the view for that controller:
{% extends partial.html.twig" %}
{% block content %}
<ul>
<li>User 1</li> (this would all be generated using 'somedata')
<li>User 2</li>
....
<ul>
{% endblock content %}
{% block scripts %}
..some javascript for interacting with this widget
{% endblock %}
This is the partial that is extended from:
{% block content %}
{% endblock content %}
{% block scripts %}{% endblock %}
Here's the main page that embeds the controller:
{% "base.html.twig" %}
{% block title %}Main{% endblock %}
{% block content %}
..some markup here
<div id="usersonline">
{% render "AppBundle:Users:usersOnline" with {'max': 4} %}
</div>
{% endblock %}
{% block scripts %}
..some javascript
{% endblock %}
This is the base that it extends:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}{% endblock %} - App</title>
...Some stylesheets
</head>
<body>
{% block content %}{% endblock %}
<script src="http://yui.yahooapis.com/3.5.0pr2/build/yui/yui-min.js"></script>
{% block scripts %}{% endblock %}
</body>
</html>
The problem I am facing now is including javascripts from the embedded controller. In my case, the view extends partial and is fully rendered as 1 unit before it is inserted into the main page. In this case, I can only put my javascript in the content block, which means I will have <script> tags within <div> tags. I would also prefer to have scripts at the end of the body for user interface performance.
How should I structure my templates (or is it even possible) so that I can render the appropriate pieces from an embedded controller's view into appropriate blocks in the template that embeds the controller? In my current template the YUI library would be loaded after the embedded controller's rendered HTML markup, so accessing using the YUI library within the embedded controller would be impossible.
I have written an extension which is essentially a token parser to deal with this. The documentation for the token parser is very sparse and the code is also mostly uncommented, so it took a bit of fiddling around to get working.
I have structured the parser so that at the beginning, you would declare something (similiar to {% use %}):
{% myparser "AppBundle:Users:usersOnline" with {'max': 4} as xyz %}
Then blocks like xyzcontent would be avaliable and then you just render them in the appropriate places using {{ block('xyzcontent') }}. It works quite well. However the following does not work:
{% set max = 4 %}
{% myparser "AppBundle:Users:usersOnline" with {'max': max} as xyz %}
I could not find a way to evaluate an expression and get its value directly within the token parser. For the most part it works fine, except for this problem.
If someone has some idea as to how to get the value of a variable within the token parser, it would be great :)
After one day of looking for a satisfying solution, I finally choose for the following approach:
Render a controller for your widget's functionality (like you are already doing);
Render templates to embed your widget's assets (controllers are not needed and will waste your performance). Ignore include if the template doesn't exist.
Use a consistent naming convention to make the widget functionality more dynamic.
Example for one widget:
{% "base.html.twig" %}
{% block title %}Main{% endblock %}
{% block content %}
..some markup here
<div id="usersonline">
{{ render(controller("AppBundle:Users:usersOnline", {'max': 4})) }}
</div>
{% endblock %}
{% block scripts %}
{{ include("AppBundle:Users:usersOnline_js.html.twig" ignore missing }}
{% endblock %}
{% block stylesheets %}
{{ include("AppBundle:Users:usersOnline_css.html.twig" ignore missing }}
{% endblock %}
(As you can see, I use the Symfony 2.2 way of including and embedding)
Or, a more dynamic way of widget rendering:
{% "base.html.twig" %}
{% block title %}Main{% endblock %}
{% block widgets %}
..some markup here
{% for widget in widgets %}
{{ render(controller(widget.controller ~ ':widget', widget.options)) }}
{% endfor %}
{% endblock %}
{% block scripts %}
{% for widget in widgets %}
{{ include(widget.controller ~ ':widget_js.html.twig' ignore missing }}
{% endfor %}
{% endblock %}
{% block stylesheets %}
{% for widget in widgets %}
{{ include(widget.controller ~ ':widget_css.html.twig' ignore missing }}
{% endfor %}
{% endblock %}
My conclusion
Rendering multiple controllers in one page, while "merging" it's templates blocks, cannot be achieved out of the box in Symfony2. Symfony2 has always been focusing on one controller for each request, which explains why multiple controllers outputs are separated and hard to combine.
I think the Symfony CMF has (or will have) a proper solution for this, because this whole widget topic is more applied in dynamic content managed websites.
Anyway, I think my way of combining embedded controllers and included templates is the best approach for Symfony 2 so far.
The alternatives, in my opinion, do have to many disadvantages:
Using multiple controllers: too heavy and not needed because assets won't need any controller.
Loading the widgets assets directly in the page: hard to maintain when changing widgets / assets.
Are there any performance differences between handcoding forms in django (as well as all the validations in the views.py) and using django's form library? If they are roughly the same, in which scenarios would one handcode a form over using the built-in ones?
Also, What about handcoding the HTML templates and using the django block tags, etc. to re-use certain areas?
Do you have insane, zero-tolerance performance requirements? As in: will people actually die or come to harm or you be fired if a page takes an extra few milliseconds to render?
I doubt it, so just let the framework do the lifting up to the point where you need more control over the HTML output -- that's actually far more likely a scenario than you needing to avoid executing some Python to save (at an utter guess) 15ms.
When you do need more control, that's when it's best to splice in some handmade HTML, or - even better - create an include/partial for form fields that you can reuse everywhere, to save you the time of manually writing more than you need to, but still giving you a lot more flexibility than myform.as_p etc
Here's a rough snippet I use and adapt a lot, to give me lots of control over form fields and also let me leverage the Django templating framework to save me time:
In my template:
{% for form_field in myform %}
{% include "path/to/partials/form_field_as_p.html" %}
{% endfor %}
And in that form_field_as_p.html, something like:
{% if not form_field.is_hidden %}
<p>
{% if form_field.errors %}
{% for error in form_field.errors %}
<span class="errorlist">{{error}}</span>
{% endfor %}
{% endif %}
{{ form_field.label_tag }}
{% if form_field.field.required %}
<span class="required">*</span>
{% endif %}
{{ form_field }}
{% if form_field.help_text %}
<span class="form-help-text">{{ form_field.help_text }}</span>
{% endif %}
</p>
{% else %}
<div>{{ form_field }}</div> {# hidden field #}
{% endif %}