How to find that the content is truncated? - django

I'm trying to build a blog app and the problem is when I use tag 'truncatewords_html' in my template to truncate posts longer than specified number of words, I need to link to complete post by some title like 'read more...' after truncation. So I should know that the post was truncated or not.
P.S.: Is this a pythonic way to solve the problem?
{% ifequal post.body|length post.body|truncatewords_html:max_words|length %}
{{ post.body|safe }}
{% else %}
{{ post.body|truncatewords_html:max_words|safe }}read more
{% endifequal %}

This is pretty convoluted but django has some weird corners. Basically I figure if the string length is the same if you truncate at x and x+1 words then the string has not been truncated...
{% ifnotequal post.body|truncatewords_html:30|length post.body|truncatewords_html:31|length %}
read more...
{% endifnotequal %}

You could write a custom template tag (see django docs), or manually check in the template, whether the content you want to display exceeds the given length via length builtin filter.

It comes down to personal preference, but for my taste you're doing way too much work in the template. I would create a method on the Post model, read_more_needed() perhaps, which returns True or False depending on the length of the text. eg:
def read_more_needed(self):
from django.utils.text import truncate_html_words
return not truncate_html_words(self.body,30)==truncate_html_words(self.body,31)
Then your template would read:
{% if post.read_more_needed %}
{{ post.body|truncatewords_html:30|safe }}read more
{% else %}
{{ post.body|safe }}
{% endif %}

Check out http://code.djangoproject.com/ticket/6799
This patch provides a method to replace the default elipses for truncated text.

Related

How to truncate/slice strings on Django Template Engine?

index.html
<td>{% if place or other_place or place_description%}{{ place}} {{ other_place}} {{place_description}}</td>
This is displaying all the data in template.I want to truncate the string if it is more than length 80.
Conditions are,
1.If place variable have more than 80 character,it should truncate their and need not show the other two variable like other_place and place_description.
2.If place variable and other_place variable making more than 80 character,in this case it should truncate from place_variable don't need to show place_description variable.
3.If all the three are their and the 80th character is made from place_description,need to truncate from their.
All fields are not mandatory,so whatever field is comes to display,it should show only 80 character.
Need help to do this.
Thanks
You could use slice for pre-django 1.4:
{% if place or other_place or place_description%}
{% with place|add:other_place|add:place_description as pl %}
{% if pl|length > 80 %}
{{pl|slice:80}}...
{% else %}
{{pl }}
{% endif %}
{% endwith %}
{% endif %}
If you are using django 1.4 or greater,
You can just use truncatechars
{% if place or other_place or place_description%}
{% with place|add:other_place|add:place_description as pl %}
{{pl|truncatechars:80}}
{% endwith %}
{% endif %}
You could probably do it with a combination of add/truncatechars e.g.
{{ place|add:other_place|add:place_description|truncatechars:80}}
You could also use 'cut' which is part of django template builtins
for example if
{{ file.pdf.name}}
gives 'store/pdfs/verma2010.pdf'
{{ file.pdf.name | cut:'store/pdfs/'}}
Would give 'verma2010.pdf'
Took me way too long to find the answer in 2022. It's truncatechars, e.g.
{{ my_string|truncatechars:1 }}
https://docs.djangoproject.com/en/3.2/ref/templates/builtins/#truncatechars

truncate characters in a HTML element - Django Templates

In my django templates i have a list of objects which is rendered as follows:
<li class="keys">
{% for key in job.key_list|slice:":2" %}
{% if not forloop.last %}
{{ key }},
{% else %}
{{ key }}
{% endif %}
{% endfor %}
</li>
This outputs the list as:
some_key, some_key_two
I want to truncate the number of characters to 20 but on the whole list. So that it renders something like:
some_key, some_key_t...
I am aware about the truncatechars and truncatewords filters available in django but they work on a string variable within the template.
How do i go about implementing this functionality ?
Wow, that's a strange requirement. You would have to implement this as a template tag or custom filter that takes a list and transforms it.
#register.filter(name='truncatinator')
def truncatinator(value, arg):
strings = ",".join(value)
if len(strings) >= arg:
part = strings[0:19] + "..."
return part.split(',')
and use it like this {% for object in job.key_list|truncatinator:"20" %}
What you will notice though is that you will loop over a string list here instead of your objects which will give you this disadvantage: You won't have access to your .id.
This could be modified though as well.
I would do this with Javascript instead but I don't think that Django should be responsible for this overall.

Control the form errors display while using {{ form.as_ul }} in Django templates.

I like the convenient output form method {{ form.as_ul }} but is there a way I can still continue to use it but capture all the errors upfront instead of displaying the error just above each field.
I understand that there are ways to loop through each form element and so on as mentioned in django docs but I want to continue to utilize the capability of form.as_ul() except get control over error display.
Solved this problem by using Reusable Form Templates.
Its simple...
Create a reusable template with the following code snippets based on your need.
If you want to display all errors right at the top of the form...
{% if form %}
{% if form.errors %}
{% for field in form %}
{{field.errors}}
{% endfor %}
{% endif %}
{% for field in form %}
<li>{{ field.label_tag }}: {{ field }}</li>
{% endfor %}
{% endif %}
If you want to display all errors right after each form field without the default html elements around error use...
{% for field in form %}
{{ field.label_tag }}: {{ field }}
{% for error in field.errors %}{{ error }}{% endfor %}
{% endfor %}
Used the second template and created a Inclusion Tag
The only way I see is to inherit the new form class from forms.Form and alter as_ul method as you like. Which isn't very good if you are going to use third-party forms like login form and so on (they won't have this method).
I think the best solution is to create your own inclusion tag and render form with it. It will be as short as as_ul ({% render_form form %}) but very flexible, it will work with all forms and won't mix HTML and Python code.
I still think the customization for rendering form in templates is quite flexible. I usually do this for my webapps. You may work with a bit javascript and css but not a big problem. Moreover, I think we should try to make the app simple.

Django TemplateTag evaluating to a boolean

Is it possible to create a Django template tag which evaluates to a boolean?
Eg, can I do:
{% if my_custom_tag %}
..
{% else %}
..
{% endif %}
At the moment I've written it as an as tag, which works fine like this:
{% my_custom_tag as var_storing_result %}
But I was just curious if I could do it the other way as I think it'd be nicer if I didn't have to assign the result to a variable first.
Thanks!
Actually.. what you can do is register tag as assignment_tag instead of simple_tag Then in your template you can just do {% my_custom_tag as var_storing_result %} one time and then regular if blocks where ever you want to evaluate the boolean. Super useful! For example
Template Tag
def my_custom_boolean_filter:
return True
register.assignment_tag(my_custom_boolean_filter)
Template
{% my_custom_boolean_filter as my_custom_boolean_filter %}
{% if my_custom_boolean_filter %}
<p>Everything is awesome!</p>
{% endif %}
Assignment Tag Official Doc
One alternative might be to define a custom filter that returns a boolean:
{% if my_variable|my_custom_boolean_filter %}
but that will only work if your tag depends on some other template variable.
You'd have to write a custom {% if %} tag of some sort to handle that. In my opinion, it's best to use what you already have in place. It works well, and is easy for any other developers to figure out what's going on.

Django - Is there a way to create a variable in the template?

I want to do this:
{% for egg in eggs %}
<p>{{ egg.spam }}</p>
{% if egg.is_cool %}
{% myvariable = egg %} // Possible in any way?
{% endif %}
{% endfor %}
Pardon the JavaScript-style comment (it shows up as a comment on SO)
I think the closest you'll get is the with tag: http://docs.djangoproject.com/en/dev/ref/templates/builtins/#with.
If you're say trying to feature an item in a template, I can imagine doing something like:
<div class="special">
{% with some_list.first as special_item %}
{{ specialitem }}
{% endwith %}
</div>
<div class="everything">
{% for item in some_list %}
{{ item }}
{% endfor %}
</div>
If you want some special logic to determine which one is the special item, I'd add a method to the object (so you end up with: {% with some_collection.my_method as special_item %} above) or determine the special item before passing it to the view. Hope that helps.
Welcome to Django Templates.
This problem is easily solved with one of the earliest snippets posted to DjangoSnippets.com: the Expr tag.
People can argue all day about the separation of logic from the templates, but that ignores that there is business logic, which belongs in the models or views, and presentation logic which belongs only in the templates. If you have a lot of presentation logic you may want to consider using Jinja2 for some or all of your templates. WARNING: although Jinja2 looks a lot like Django's template language, there are incompatibilities with things like Custom Template Tags.
Yes, you can use the with construct:
{% with myvariable as egg %}
do stuf
{% endwith %}
I think it's probably best to do this kind of test-and-set behaviour in the view, not the template. If anything, it'll give you better control over cacheing if/when you need it.