store html templates in docstrings? - python

I am using Flask to write a web service for an internal app here at my work. Many of the web services URI's return HTML partials, and I am trying to figure out a clean way to store the html template strings. I don't want to put the template strings in separate files, since they are usually only a few lines long and I don't want to have 20 template files that each have 3 lines in them. I was thinking about defining a function's html template string in the docstring of the function, as I feel like that would serve multiple purposes. It would serve as documentation, basically saying "this is what I output", as well as keeping me from having to store 3-line templates strings in separate files. Here is what I am talking about:
#app.route('/path/to/my/resource/<int:_id>')
def some_resource(_id):
"""
<select id="resource-{{ resource.id }}" class="resource">
{% for choice in choices %}
<option id="choice-{{ choice.id }}" value="{{ choice.id }}">
{{ choice.text }}
</option>
{% endfor %}
</select>
"""
# retrieving resource, etc...
return render_template_string(some_resource.__doc__, **kwargs)
I don't know whether this would be a nightmare to maintain or not...any thoughts?

I think its a bad plan.
Docstrings are for documentation, the template is not documentation. Documentation is supposed to describe what the function is being used for. An HTML template is a poor substitute for that.
You can use multi-line strings to hold your template, and thats probably a good idea. You don't gain anything by making them docstrings.

It's certainly an interesting idea, and following the example of doctest, it's not entirely unheard of to put functionally-useful things in your docstrings instead of just text. The obvious drawback is that then there's no documentation in the docstring. Now, this may or may not be a huge problem if the methods are not something that programmers will likely need documentation on via help() (or by auto-generated docs using the docstrings).
However, why not either:
just use a local string variable - the downside would be that you can't get at it via __doc__ from outside the scope of the function
if it's just used that once, just put it into the render_template_string call - same drawbacks as #1, but also doesn't apply if it's used more than once
create another decorator that takes this string as an argument - especially if it just follows the pattern above where you're just using it the once and you're always doing the same call at the end, this would allow you to pull it out of that method

In some templating engines, if an object has a __html__ method, it's output is treated as a safe (escaped) string.
def fn(x):
bla = x
fn.__html__ = lambda : '''
<h1>Headline</h1>
<p>lorem ipsum</p>
'''

Related

Jinja2 dynamic variable building

My jinja template gets an object which has many variable names, this attributes vary and so their names, I am looking for a way to access this attributes based on a prefix and a for loop:
{% for i in Object.vars %}
<h1> {{ Object.attribute_ + i }} </h1>
{% endfor %}
I'm trying to access Object.attribute_1, Object.attribute_2 and so on. the code above of course won't work, but I can't think on a way of doing this.
Keep in mind that doing too much logic in your template files will cause (long term) issues to maintain your code.
I would say, keep your logic outside of the template and create a list of your objects before rendering the template, using the getattr() function:
for i in Object.vars:
list_of_objects.append(getattr(Object, 'attribute_' + i))
Now when rendering the template pass the list to like that:
render_template('page.html', list_of_objects=list_of_objects)
The canonical way to solve problems like this is to pass a structure such as a list or dict. Dynamic variable names are almost always a terrible idea.

django get first part of a string

Is there a simple django tag to get the first x characters of a string in a template?
In a list of modelinstances, I would like to give a different symbol per objectinstance, depending on the status of the objectinstance. Status could be 'waiting', 'success' or 'failed XXXX', with XXXX being the errorcode.
I would like to check if the first 5 characters of objectinstance.status == 'error', then the symbol will be red. However, how can I do this? In Python I could use objectinstance.status[:5].
Using https://docs.djangoproject.com/en/dev/ref/templates/builtins/ I managed to do this with following 'monstruous' concatenation, but is there something simple as .left() or .right()?
{% if run.status|make_list|slice:":5"|join:"" == 'error' %}
You could try:
{% if run.status|truncatechars:5 == 'error...' %}
(See truncatechars in the Django docs)
Although I might say, as an overall point, you shouldn't be putting this kind of logic in your Django templates (views in other frameworks). You want to put this into the Django view (controller in other framerworks). Meaning, you would something like this in your view:
has_error = run.status.startswith('error')
Ensure has_error is passed to the template and:
{% if has_error %}
It may be more work, but the logic to detect error conditions could be shared between multiple views and templates, and you separate control logic from view logic.
If you use Django 1.4+ you can use the truncatechars tag but it will only solve partially your answer and will add ellipsis at the end.
The only viable way, a part from concatenating many filters as you already did, is to write a custom filter. Here is a first draft you can customize:
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter
#stringfilter
def slicestring(value, arg):
"""usage: "mylongstring"|slicestring:"2:4" """
els = map(int, arg.split(':'))
return value[els[0]:els[1]]
as a bonus this filter allows you to mimic almost completely the slice notation by providing a "slicing string" as the argument. The only exception seems the syntax [:9] that has to be replaced with [0:9], thus with this argument: yourvariable|slicestring:"0:9"
A side note: Since your question is "getting the first part of a string" I believe a custom filter may be the correct answer, however if the only reason to get a sliced string is to check for a part of it inside an if statement, then I have to agree with Anton: you should place your checks inside the view, not inside the template, when possible.

How can I use Django built-in filters with Jinja2 using Appengine SDK?

I've tried several different ways a while ago, each of them gave a different exception, so I gave up and decided to manually write filters when I need them. But I'm missing the native escapejs and other useful but simple filters.
There are several related questions and answers, but as far as I see none of them gives a seamless way to implement this. I guess the main problem is that django filters routines are tied too much to the django environment.
Please answer only if you managed to use built-in django filters in the Appengine SDK environment, from my experience it's harder compared to a normal environment, as Appengine environment is limited
Template tags in the Django template engine are simple functions that accept values and parameters. They can all be accessed directly in the source code.
This is output from IPython:
In [173]: from django.template.defaultfilters import date
In [174]: date??
Type: function
String Form:<function date at 0xa2935f0>
File: /usr/local/python/thor/lib/python2.7/site-packages/django/template/defaultfilters.py
Definition: date(value, arg=None)
Source:
#register.filter(expects_localtime=True, is_safe=False)
def date(value, arg=None):
"""Formats a date according to the given format."""
if not value:
return u''
if arg is None:
arg = settings.DATE_FORMAT
try:
return formats.date_format(value, arg)
except AttributeError:
try:
return format(value, arg)
except AttributeError:
return ''
Most of the Django-specific magic resides in the decorator (register.filter) and in the way that the language resolves calls when you type {% load <template library> %} in your template. Look for the definitions in <module>.templatetags modules. Built-ins are located in django.template.defaulttags and django.template.defaultfilters.
If Jinja2 has a way to define new template filters (which it probably does), then you could simply wrap handmade template filters to actual Django functions.
So basically, just create Jinja2 filters that point to the actual Django function definitions.
Edit:
If you do not have access to the actual Django functions, just copy-paste the source code and remove or adapt Django-specific stuff.
The escapejs filter is actually a call to this function in django.utils.html:
_base_js_escapes = (
('\\', r'\u005C'),
('\'', r'\u0027'),
('"', r'\u0022'),
('>', r'\u003E'),
('<', r'\u003C'),
('&', r'\u0026'),
('=', r'\u003D'),
('-', r'\u002D'),
(';', r'\u003B'),
(u'\u2028', r'\u2028'),
(u'\u2029', r'\u2029')
)
# Escape every ASCII character with a value less than 32.
_js_escapes = (_base_js_escapes +
tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
def escapejs(value):
"""Hex encodes characters for use in JavaScript strings."""
for bad, good in _js_escapes:
value = mark_safe(force_unicode(value).replace(bad, good))
return value
I alluded to this in my comment, but I'll be more specific here since I have more space. Django is an end-to-end web application framework, which happens to include its own template language, that for lack of a better term is just called the "Django template language". All the template tags and filters in the docs are specific to that language.
If you choose to use Jinja2, you choose to use that template language's structures to the exclusion of Django's. (Obviously the model and view stuff is a separate layer, but in principle, those could be swapped too--it's all loosely coupled.) So the Django docs for templating are no good to you in that case. If you want to format a float in Jinja2, it looks like you need to use the format filter, according to the Jinja docs.
Without more info, I really can't say what's causing your ImportError, but floatformat is not going to work in a Jinja2 template, so maybe that has something to do with it.

Injecting values from a child template into a parent template in Jinja2

I have created a Jinja2 template called lesson.html that defines the basic structure of a lesson. From that, I derive one child template for each actual lesson (since the content of each lesson is different). For example, intro.html, variables.html, lists.html, and functions.html all derive from lesson.html.
Along with slides, exercises, and what-not, each actual lesson has a YouTube video. I want to put the ID of the video in the child template file, but then put the HTML that actually references videos in the parent template (i.e., lesson.html) to ensure that every video is referenced and formatted the same way. For example, I would like lesson.html to look like:
<div class="youtube"><br/>
<iframe title="{{TITLE}}" time="{{TIME}}" src="http://www.youtube.com/embed/{{ID}}"></iframe>
<br/>
</div>
and then have TITLE, TIME, and ID all defined in the child template file itself (since that's the most logical place to store them). My current hack is to create a function that takes these values as arguments and returns a blob of HTML to be inserted in the right place:
{{youtube("Title of this Lecture", "abcde01234", "05:10")|safe}}
but (a) I'd rather use straight template expansion than function calls, and (b) the title, YouTube ID, and time aren't explicitly identified in the lesson template file (which makes them harder to extract for use elsewhere: I can do it with regular expressions, but I'd really rather not).
Is there a clean way to define values in a child template for use in a parent template?
You can use set, DOC are as follows:
Inside code blocks, you can also assign values to variables. Assignments at top level (outside of blocks, macros or loops) are exported from the template like top level macros and can be imported by other templates.
Same question can be found here.

Jinja2: Looking for a View-Helper

I'am new to the Jinja2 template engine. Is there something like the view-helpers from Zend Framework? Can i create simple functions and reuse them all over all my template-files?
Something like this?
#somewhere in my python code:
def nice_demo_function(message):
""""return a simple message"""
return message
So i can to use that:
<!-- now in my template-file -->
{% nice_demo_function('yes, this works great!') %}
There are a number of ways you can expose helper functions to your templates. You could define them using macros, and then import them into templates that use them. You could add functions to the globals attribute of your Template objects, or pass them to the render() method. You could subclass Template to do the same without having to repeat yourself each time. If you want to get really fancy, you could look into writing extensions as well (but you probably don't need to go that deep).
At some point you will have created a Jinja2 environment. The environment has an attribute on it called filters which is a dict that maps names to functions. So what you want to do is:
def my_helper(value):
return "-~*#--- %s ---#*~-" % value
env = Jinja2.Environment(...)
env.filters['my_helper'] = my_helper
Now in your template you can do:
<p>The winner is {{ winner | my_helper }}</p>
And your function will be called with the value of the variable, in this case winner. If you are using Pylons, this all happens in config/environment.py.

Categories