Can't substring in Django template tag - django

I am trying to add a trailing 's' to a string unless the string's last character is an 's'. How do I do this in a Django template? The [-1] below is causing an error:
{{ name }}{% if name[-1] != "s" %}s{% endif %}

try the slice filter
{% if name|slice:"-1" != "s" %}

{% if name|slice:"-1:"|first != "s" %}s{% endif %}
Django's slice filter doesn't handle colon-less slices correctly so the slice:"-1" solution does not work. Leveraging the |first filter in addition, seems to do the trick.

The Django template system provides tags which function similarly to some programming constructs – an if tag for boolean tests, a for
tag for looping, etc. – but these are not simply executed as the
corresponding Python code, and the template system will not execute
arbitrary Python expressions.
Use the slice built-in filter.

Not sure if this is what you're looking for, but django has a built-in template filter that pluralizes words. It's called just that: pluralize.
You'd want something like this:
{{name | pluralize}}
Take a look at https://docs.djangoproject.com/en/dev/ref/templates/builtins/

{% if name|last != "s" %} does the job

Related

Django-templates: Concatenate string variables with strings in with block

So I'm looking to do something like this to keep things DRY:
{% with share_text=author.name + "released" + book.title + "via:myapp" %}
do stuff with {{share_text}}
{% endwith %}
However, I'm getting Django template errors like "could not parse remainder" and "with received invalid operator +".
Django template language is NOT python (ever if it sometimes looks a bit similar), so don't expect python code to work here. Use template filters / tags. In your case the builtin add templatefilter should work:
{% with share_text=author.name|add:"released"|add:book.title|add:"via:myapp" %}
but please carefully read the limitations and gotchas mentioned in the doc. Else you can write your own custom filter or templatetag, that's really easy.

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?

Combining "with" and "url" Django Template Tags

Django has two template tags "with" and "url". It would be handy to be able to combine the two:
{% with view=really.long.path.to.some.view.somewhere %}
{% url view.foo %}
{% endwith %}
But if you try doing that, you find out that the "with" isn't getting applied inside the "url" tag (as you get an error about there not being a "view.foo").
So, my question is, am I just missing some flag/option/alternative format that would make the above work, or is truly impossible to simplify "url" tags using "with"?
It is possible in Django 1.3 if you're willing to use a future compatibility library.
See the section Forwards compatibility at https://docs.djangoproject.com/en/dev/ref/templates/builtins/#url (just above the discussion on widthratio) for an explanation and examples.

Django templates - split string to array

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.

Is there any reason why you can't compare a template filter to a string in Django template syntax?

I'm trying to do this, and failing. Is there any reason why it wouldn't work in Django template syntax? I'm using the latest version of Django.
{% ifequal entry.created_at|timesince "0 minutes" %}
It doesn't work because it's not supposed to work. What you're asking for is not part of the template language.
You can't apply a filter in the middle of tag like {% ifequal. When a template tag uses a variable, it doesn't expect an expression, it expects a variable, nothing more.
That kind of logic -- extracting time since, comparing, etc. -- is what you're supposed to do in your view function.
Your view function then puts a "zerominutes" item in the context for the template to use. Templates just can't do much processing.
They're designed to do the minimum required to render HTML. Everything else needs to be in your view function.
{% ifequal %} tag doesn't support filter expressions as arguments. It treats whole entry.created_at|timesince as identifier of the variable.
Quik workaround: introduce intermediate variable with expresion result using {% with %} like this:
{% with entry.created_at|timesince as delta %}
{% ifequal delta "0 minutes" %}
....
{% endifequal %}
{% endwith %}
See ticket #5756 and links in its comments for more information. A patch for Django in ticket #7295 implements this functionality. A broader refactoring of the template system based on #7295 is proposed in ticket #7806, and it would fix this issue among others.
I don't think making such comparisons to work would be against the design philosophy of Django templates.
I think you can, though I don't see any uses of it my code base. Maybe entry.created_at|timesince isn't producing the value you expect. Try putting
X{{entry.created_at|timesince}}X
into your template and seeing what value it produces. The X's are so you can see leading or trailing space, in case that is the problem.
I finally gave up on using the Django template language for anything other than the simplest pages. Check out Jinja2 for an almost-syntax-compatible alternative. And yes, you can choose which to use on a page-by-page basis.