Display unescaped HTML String in Django Admin change list - django

I am currently facing a serious problem.
I use the standard django admin interface incl. change list to display one of my models.
The model has got a field, which includes a link (e.g. in database: http://localhost:8000/data/somefile.pdf'>link).
What I want now is that this string is rendered unescaped and displayed as link. I already tried the following in "change_list_results.html":
{% for result in results %}
<tr id="{{ result.1|adminfilter }}" class="{% cycle 'row1' 'row2' %}">
{% for item in result %}
{{ item|safe }}
{% endfor %}</tr>
{% endfor %}
I used "|safe" on the actual item that is output. Furthermore i tried "{% autoescape off %}". Same result, the String got escaped.
Do you see any other way to get the String displayed unescaped?

You want to set allow_tags=True on your method. It's a bit hidden, but it is described in the documentation - about a screen or so down from where this link takes you.

Related

django template language - if statement issues

i am kind of new to django and i ran into a problem i couldnt find a solution to. In a template i render data from a custom context processor. There i use a for loop over all the queried items and a if statement, that checks that the data belongs to the person that is currently logged in:
{% for item in all_soli_accs %}
{% if item.owner == request.user.get_username %}
<a href="{% url 'url-soli-acc' item.soli_acc %} ">
{{ item.soli_acc }}
</a>
{% endif %}
{% endfor %}
Weirdly, the if statement doesnt return "true", when it is supposed to. The rendering doesnt output anything. In order to debug it, i tried to render {{item.owner}} and {{request.user.get_username}} and check if there are errors. But rendered as a variable, they return the same output, which lets me assume that it is all fine. I am confused. Does anyone has a solution to that? Do you need further information?
best regards
Use
request.user.username
Instead of
request.user.get_username

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.

Using django-haystack, how do I order results by content type

I'm using django-haystack for a search page on my site, and I want to order all the results by their content type. Is there a way I can do that?
To make it simpler, suppose I have a single application and several classes.
Thanks in advance
Not sure what you mean by content type, but if you are talking about group by models, I have this working
{% with page.object_list as results %}
{% regroup results|dictsort:"verbose_name_plural" by verbose_name_plural as grouped_objects %}
{% for ct in grouped_objects %}
{{ ct.grouper }}
{% for result in ct.list %}
<p>
{{ result.object }}
</p>
{% endfor %}
{% empty %}
<p>No results found.</p>
{% endfor %}
{% endwith %}
from How to order search results by Model:
You can do
SearchQuerySet().order_by('django_ct').
As a warning, this throws out
relevancy. The only way to keep
relevancy & group by model is either
to run many queries (one per model -
usually performant thanks to query
caching) or to run the query and
post-process the results, regrouping
them as you go.
from searchindex api:
Haystack reserves the following field
names for internal use: id, django_ct,
django_id & content. The name & type
names used to be reserved but no
longer are.
You can override these field names
using the HAYSTACK_ID_FIELD,
HAYSTACK_DJANGO_CT_FIELD &
HAYSTACK_DJANGO_ID_FIELD if needed.

How to find that the content is truncated?

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.