Django templates - split string to array - django

I have a model field, which stores a list of URLs (yeah, I know, that's wrong way) as url1\nurl2\nurl3<...>. I need to split the field into an array in my template, so I created the custom filter:
#register.filter(name='split')
def split(value, arg):
return value.split(arg)
I use it this way:
{% with game.screenshots|split:"\n" as screens %}
{% for screen in screens %}
{{ screen }}<br>
{% endfor %}
{% endwith %}
but as I can see, split doesn't want to work: I get output like url1 url2 url3 (with linebreaks if I look at the source). Why?

Django intentionally leaves out many types of templatetags to discourage you from doing too much processing in the template. (Unfortunately, people usually just add these types of templatetags themselves.)
This is a perfect example of something that should be in your model not your template.
class Game(models.Model):
...
def screenshots_as_list(self):
return self.screenshots.split('\n')
Then, in your template, you just do:
{% for screen in game.screenshots_as_list %}
{{ screen }}<br>
{% endfor %}
Much more clear and much easier to work with.

Functionality already exists with linkebreaksbr:
{{ value|linebreaksbr }}
https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#linebreaksbr

Hm, I have partly solved this problem. I changed my filter to:
#register.filter(name='split')
def split(value, arg):
return value.split('\n')
Why it didn't work with the original code?

I wanted to split a list of words to get a word count, and it turns out there is a filter for that:
{{ value|wordcount }}
https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#wordcount

Apart from whether your original solution was the right approach, I guess the original code did not work because the meaning of the \n is not the same in Python code as it is in HTML: In Python code it means the escaped newline character, in HTML it is just the two separate characters \ and n.
So passing as input parameter \n from the HTML template to the Python code is equivalent to splitting on the Python string \\n: a literal \ followed by a n.

Related

what is difference between {{}} and {% %} in django templates

I am very new to django and working on it.. I visited a html file and dont know the difference between {{}} and {% %} in html files used
as here
{% load static %}
Thanks a lot
You can use
{% %} For sentences such as if and for or to call tags such as load, static, etc.
{{ }} To render variables in the template.
Read More about it at Django Docs
{% %} is for displaying code and {{}} is for displaying variables
There are three things in the template in Django
First is template variable and the second thing is template tag and third and last is template filter
so we write a template variable is {{}}
and write a template tag is {% %}
third and last is template filter {{variable |filter:arg}}
I'm new too for Django, so if i'm wrong, please someone correct me.
The difference between they are:
{{variable}} is used to use a variables. When the template encounters a variable, it evaluates that variable and replaces it with the result.
You also can use filters {{variable|filter}} like this:
{{name|length}} in this case you will use a variable "name" and return the length of that variable.
{%tag%} could use for loops or logic, or load external information into the template to be used by later variables. You can create block tags to help extend other html files parts. Also you can create custom tags.
A good place to see how to do it:
https://www.codementor.io/hiteshgarg14/creating-custom-template-tags-in-django-application-58wvmqm5f
Tags like loops and block, need to be closed.
{% %} for IF ELSE CONDITIONS and FOR LOOP etc
{{ }} for veriables that rendered from view function also used in FOR LOOP veriables like
`enter code here`
{% for obj in qs%}
{{ obj.veriable_name }}
{% endfor %}

Django templates - comparing variables to integer constants

Seems like elementary question, and yet can't get it work
{% if iterator.next > 10 %}
Do smth
{% endif %}
Two issues. First, this code just won't work (the code in the if-condition never implemented even when the condition seems to hold true), and second issue - the ">" sign is highlighted as if it where the closing tag of the closest open tag. Any ideas how to fix the first issue and is it all right with second issues ? Maybe there's some elegant syntax that I am missing and that would remove this ambiguity for the text editor ?
iterator.next may be a string which would result in the statement being False.
Try creating a custom filter to convert it to an int. For example create "my_filters.py":
# templatetags/my_filters.py
from django import template
register = template.Library()
#register.filter()
def to_int(value):
return int(value)
Then in your template:
{% load my_filters %}
{% if iterator.next|to_int > 10 %}
Do smth
{% endif %}
More on custom tags and filters here
I wouldn't worry about the highlighting, this may just be your IDE. I recommend using PyCharm for Django development
Django's docs says that you can use > with if tag:
{% if somevar < 100 %}
This appears if variable somevar is less than 100.
{% endif %}
take a look at documentation: https://docs.djangoproject.com/en/1.9/ref/templates/builtins/
maybe you are missing something else?

How can I truncate a text and use the second part of the text?

I'm researching for a little problem.
I get on my Django template a text. The point is truncate that text, and add the second part of the text in other tag.
I read about:
{{ value|truncatechars_html:x }}
It can works, but I can't use the second part of truncated text.
If someone has an idea...Thanks!!!!
Use slice - see docs here. Strings in python are also lists of characters, so you can do something like this:
First part is {{ value|slice:":x" }}
Second part is {{ value|slice:"x+1:" }}
HOWEVER, if you need to keep some html code, slice won't do it. For that, you will need to write your own custom tag (you can look into the code from truncate chars) which returns two values - one for each part of your string.
Assuming your filter returns something like this:
def your_truncate_filter(value, arg):
... # your code for splitting
data = {}
data['first'] = "....." # first part of string with html tags !!!
data['second'] = "....." # second part of string
return data
you can access it in your template like this:
{% with parts=value|your_truncate_filter:x %}
{{ parts.first }}
{{ parts.second }}
{% endwith %}

Django template variable containing template tag, ex {{ {% some_tag %} }}

I have a template that receives a list context variable, tags_list. I need to iterate over this list 'inserting' the tags in the template something like this:
{% for tag in tags_list %}
{{ tag.tag }}
{% endfor %}
When this renders it returns the text value of tag.tag, "{% tagxxx %}", not the rendered tag.
How can I cause the template render to render the value of a context variable? Alternately, is there a filter, a sort of inverse verbatim, that will cause the value of a context variable to be rendered?
Updated background
tags_list is created by a fairly sophisticated process involving exec of some user provided text from a table/model field. The relevant portion of the real template looks like this:
{% for graph_row in graph_rows %}
<div class="row">
{% for graph in graph_row %}
<div class="col-md-{{ graph.width }}">
{{ graph.graph }}
</div>
{% endfor %}
</div>
{% endfor %}
The graph values look like this: {'graph':'{% piechart data1 %}', 'width':3}
Note that the order of entries in the context variable graph_rows is significant as is order of graph(s) in the row as that determines the placement of graphs on the page. Preserving this order is essential for the scheme to work correctly.
Currently, the view function simply does an {% include ... %} to get the template segment above to render in the correct order. This approach is simple and clean.
I could, as has been suggested, perform a template render within the view function but that complicates the design a bit and I'd hoped to avoid doing that if there is an easy way to trigger a render of {{ graph.graph }}. Note, as well, by moving the render into the view I loose the ability to easily take the template from arbitrary places, in particular table fields.
One of the great things about Django is the library of solution and code snippets. Sadly, they aren't a well organized and easy to find as one might wish. Nevertheless, a bit of google found a number of solutions of the general form
{% render tag.tag %}
Here are links to several:
render_as_template template tag
Allow template tags in a Flatpage's content
render_as_template.py
I'll use the general approach cleaned up a bit for error checking.
As an aside, the technique strikes me as generally useful and might be appropriate for inclusion in the standard tags.
Update 3/28/2014
After looking at the above and several others this is what I used from render_as_template template tag. There is a useful comment here.
from django import template
from django.template import Template, Variable, TemplateSyntaxError
register = template.Library()
class RenderAsTemplateNode(template.Node):
def __init__(self, item_to_be_rendered):
self.item_to_be_rendered = Variable(item_to_be_rendered)
def render(self, context):
try:
actual_item = self.item_to_be_rendered.resolve(context)
return Template(actual_item).render(context)
except template.VariableDoesNotExist:
return ''
def render_as_template(parser, token):
bits = token.split_contents()
if len(bits) !=2:
raise TemplateSyntaxError("'%s' takes only one argument"
" (a variable representing a template to render)" % bits[0])
return RenderAsTemplateNode(bits[1])
render_as_template = register.tag(render_as_template)
This gets part of the way to a solution. Unfortunately custom template tags, in my case
{% pie_chart %} are not available to render within the class RenderAsTemplateNode.
I've not tested this but it appears that this stack overflow question, Django - replacing built-in templatetag by custom tag for a whole site without {% load .. %}, points the way.
I believe I can provide a way for you to get the results you want, but there might be a better way for you to achieve the desired functionality if you can provide some context.
Anyway, you might do something like this in your view.py:
tags_list = [
Template('{% load my_tags %}{% ' + t.tag + ' %}').render(Context())
for t in tags_list
]

Customizing django object parameters value output

what does django do, when i do something like that in template
{{ object.parameter }}
I ask this because in case of arrayfields (postgresql array fields) it will print out either
{'value', 'value', 'value'}
(because thats how postgresql stores arrays in arrayfields)
or
['value','value','value']
if i use fields post_init method to convert postgresql array to python list.
Desired output would of course be value, value, value. I would rather not use some kind of filters for that, because then i would have to resort using IFs in templates or use some kind of template tag filter for every value i print out and that does not feel like a smart thing to do.
By the way, i know i can do something like that in template :
{% for choice in field.choices %}
{{ choice }}
{% if forloop.last %}
{% else %},
{% endif%}
{% endfor %}
and that gives me exactly what i want, but i thought there would be some other way doing it - with some modelfield method or something.
Alan
what does django do, when i do something like that in template
{{ object.parameter }}
See variables and lookups.
Desired output would of course be value, value, value. I would rather not use some kind of filters for that, because then i would have to resort using IFs in templates or use some kind of template tag filter for every value i print out and that does not feel like a smart thing to do.
You can make a really trivial filter:
#register.filter
def comma_join(values):
return u', '.join(values)
So simple:
{{ object.parameter|comma_join }}
Why would you want to avoid such a simple solution ?
and that gives me exactly what i want, but i thought there would be some other way doing it - with some modelfield method or something.
Of course you could also add such a method:
class YourModel(models.Model):
# ....
def comma_join_parameter(self):
return u', '.join(self.parameter)
And use it in your template as such:
{{ object.comma_join_parameter }}