Django Template Wont Display Complex String - django

I've got a list in my view, and I am trying to output it to a template. The code for this is:
{% for user in list %}
<tr class="{{ user.1 }}">
{% for item in user %}
<td class="{% autoescape off %}{{item}}{% endautoescape %}">{% autoescape off %}{{item}}{% endautoescape %}</td>
{%endfor%}
</tr>
{%endfor%}
The code itself works fine, however it will not print an element in the list if it is overly complex. It has no issue printing the same element if it is "test", however when it is populated with actual data, it displays a blank field, an moves onto the next element.
I cannot show you the exact data, but it contains speech marks, slashes, various letters and sometimes a percent. the string is usually around 25 chars long,Thank you!
EDIT: Thought I'd add that playing with autoescape doesn't help
The data that i'm trying to output is:
b"\x11\xb4\xc7\xabhM#\x04\x87\x00\xb9kV\xeet\x9d'[\xfb\x7f\x9bE\xd1P"
The entire list is:
[2, '<client>', '<acc_no>', '<username>', False, b"\x11\xb4\xc7\xabhM#\x04\x87\x00\xb9kV\xeet\x9d'[\xfb\x7f\x9bE\xd1P", 0]]

Related

How to render an arbitrary set of key->value pairs from a JSONField in a Jinja2 template?

I'm trying to add debug information to a frontend; for reasons that don't need to be gone into at the moment I'm storing the pertinent information in a JSONField.
Storing and retrieving the information works correctly, but when I try to render it via J2 to the page it's supposed to be at I'm running into some issues.
Here's the segment in question:
{% for log in connection.debug_logs.all %}
<tr>
<td></td>
<td>{{ log.log_message }}</td>
<td>
{% for key in log.log_data %}
{{ key }}: {{ log.log_data.key }} <br/>
{% endfor %}
</td>
</tr>
{% endfor %}
What I'm hoping for is for that to produce a series of lines of key: value. What I'm getting instead is:
<td>Login requested by vmx1.internal (11.22.33.44)</td>
<td>
Framed-Route: <br/>
Service-Type: <br/>
Framed-IP-Address: <br/>
Framed-IPv6-Route: <br/>
control:Auth-Type: <br/>
Framed-IPv6-Prefix: <br/>
Delegated-IPv6-Prefix: <br/>
ERX-Egress-Policy-Name: <br/>
ERX-Ingress-Policy-Name: <br/>
ERX-Virtual-Router-Name: <br/>
control:Cleartext-Password: <br/>
</td>
Using {{ log.log_data | pprint }} does yield the keys and values, but renders them as a plaintext JSON string which gets flattened by the html renderer and isn't terribly useful for debugging purposes.
Trying 'log.log_data[key]' instead yields a 'Could not parse the remainder' error.
I've tried the suggestions in this question as well as these and a few others that came up during google searches, but none of them seem to address this issue -- all of them are either working with known keys, working with an actual dict instead of a JSONField, or sometimes both.
I'm probably missing something very simple and straightforward, but I've run out of ways to phrase my question in a search engine. Any tips?
EDIT No, it is not actually a dictionary. I've also tried the solutions in this answer and that leads back to the Could not parse the remainder error.
So the data I'm looking for is absolutely there, I'm just having issues trying to get it to render properly.
Third and final edit: The problem was apparently that Django templates are not quite Jinja2 templates, and rather than {% for key, value in log.log_data.items() %} I needed to use {% for key, value in log.log_data.items %}
Do the conversion from json inside your view to have a greater range of utilities than inside the jinja2 template world.
import json
DEBUG_LOGS_JSON = "[
{"log_data": {"Framed-Route": "route1", "Service-Type": "type1"}, "log_message": "my"},
{"log_data": {"Framed-Route": "route2", "Service-Type": "type2"}, "log_message": "name"},
{"log_data": {"Framed-Route": "route3", "Service-Type": "type3"}, "log_message": "Tarquinius"},
]"
def my_view(request):
my_dict = json.loads(DEBUG_LOGS_JSON) # instead you could also restructure the data passed to the template here.
return render("my_template.html", context=my_dict)
{% for dictionary in my_dict %}
<tr>
<td>{{ dictionary.log_message }}</td>
<td>
{% for key, value in dictionary.log_data.items() %}
{{ key }}: {{ value }} <br/>
{% endfor %}
</td>
</tr>
{% endfor %}
If this does not represent the structure of your json, then please provide an example. Let me know how it goes.

Replace function inside value not working

Maybe I'm doing it wrong (tried several ways to achieve my goal) or overlooking something here.
What I'd like to achieve is this:
When I use the Live-search function, I get categories containing the search keyword (like: Paint -> Paint buckets, Paint brushes, Paint colors etc.) which works like a charm. The one thing I need is to style the searched keyword in the presented categories like:
Paint bucket,
Paint brushes,
Color paint
This is the code I have at the moment:
{% if (products.length + categories.length + pages.length) == 0 %}
<div id="Pi56dYpB" class="undefined"> No results for:
<b>{{ query }}</b>...
</div>
{% endif %}
{% if categories.length > 0 %}
<div class="categories">
{% for category in categories %}
{% if loop.index < 7 %}
<a class="p-0" href="{{ category.url }}" style="all:inherit;">
<h3 id="bvwiyjEN" class="undefined">{{ category.name|replace({{ query }}: "<strong>"{{ query }}"<strong>"})|raw }}</h3>
</a>
{% endif %}
{% endfor %}
{% endif %}
Unfortunately this isn't working. I did check if the {{ query }} value is accessible with this simple line of code:
<h3 id="bvwiyjEN" class="undefined">{{ category.name }} - {{ query }}</h3>
No problems found here.
Did I use the wrong syntax in my code maybe? Any help would be appreciated!
replace({{ query }}) is the wrong syntax - replace(query) should work, as you don't want to echo the variable query here
As Nico Haase pointed out already, {{ ... }} is used to output variables, this translate to something like <?php echo $foo; ?> and can't/shouldn't be used inside statements
Furthermore, the filter replace expects an array of keys to replace with the values.
You would need to change your code to the following:
{% for category in categories %}
{{ category|replace({ (query): '<strong>'~query~'</strong>',})|raw }}
{% endfor %}
demo
Some notes:
The filter replace uses the PHP function strtr in the background. This mean the output will be case-sensitive. If you don't want this, I'd advice you to follow through here
Wrapping the key with parantheses is mandatory. This will force twig to evaluate/interpolate the value of the key - demo

How to truncatechars of wagtail streamfield block?

After reading all the docs, I still don't know how to truncatechars of a wagtail streamfield blocks.
{% for block in post.body %}
{% if block.block_type == 'richtext' %}
{{ block.value|truncatechars:100 }}
{% endif %}
{% endfor %}
works with weird results depending on quantity of truncatechars - if it's definitely above the number of characters of all the streamfields, it displays everything (all) as expected; Now i'm putting 40 and it displays:
First rich…
third ric…
fifth …
(my text streamfields are "first richtext", "third richtext" and "fifth richtext" ; second and third blocks are pics successfully filtered out )
I think it could be fixed by adding all of the blocks into one for output, but I don't know how to do it. Do I iterate ? There's no "+" tag :/
{{ post.body|first|truncatechars:200 }}
Is a working temporary fix, it isn't perfect because now I need to force admins to make their first streafield block a text and make it of enough length.

Parsing and using list item content via Twig

I am experimenting with using Grav to create my next website. One of the things I would be able to do is to build a unordered list using data provided in Grav frontmatter from the Grav page that uses the template. Here is how I am trying to do this
---
sectionone:
listitems: "['Benefit 1','Benefit 2','Benefit 3']"
---
and then in the template somehow do the following
{% block featurelist %}
<ul>
{% set items = {{page.header.sectionone.consumers.benefits|json_decode}} %}
{% for item in {{}} %}
<li>{{item}}</li>
{% endfor %}
</ul>
{% endblock %}
However, Twig does not like this and reports back an error along the lines of
Twig_Error_Syntax
A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "punctuation" of value "{".
with the offending line being my {% set items = ... } statement. I am clearly doing something wrong here but I am a Twig newbie so I fail to see what that might be.
{% block featurelist %}
<ul>
{% set items = page.header.sectionone.consumers.benefits|json_decode %}
{% for item in items %}
<li>{{item}}</li>
{% endfor %}
</ul>
{% endblock %}
I figured this out eventually. Grav documentation is by and large very good. However, the documentation on page headers/frontmatter appears to be somewhat incomplete. There is no full description of the entire syntax that is understood by the frontmatter processor. In order to define an array in front matter all you need to do is the following
---
sectionone:
benefits:
- 'Benefit 1'
- 'Benefit 2'
- ...
---
In essence the standard markdown syntax for an unordered list. Grav's twig processor appears to convert this to a PHP array - no parsing required!

Breaking data into multiple display columns with Django

Overlap in terminology makes search for answers difficult for this one.
I'm looking for advice on the best way to implement a multiple-column display of my QuerySet that fills each column top to bottom over X columns. Meaning that the number of items in each column equals the QuerySet count divided by X (number of columns).
Using Offset doesn't work for this because I would like my data to grow into 4 columns without updating the offset manually. CSS floats work visually, but leave the data out of order.
Something like that should work for you, pass the number of columns as columns to the template:
{% for item in items %}
{% if forloop.first %}<div style="float:left;">{% endif %}
{{ item }}
{% if forloop.counter|divisibleby:columns %}
</div><div style="float:left">
{% endif %}
{% if forloop.last %}</div>{% endif %}
{% endfor %}
<div style="clear:both;"></div>
It seems like lazerscience's answer is on the right track - but I think the OP wants the data to alphabetically sort the data down the column and then start back at the top of the next column. Using divisibleby: works to break the line after 'X' items, but I think it'll take a more complex template to do what the OP wants.
Not sure if it's possible, but in the view could you: Get item count, divide by 'columns' and used that # in Divisibleby to break into the next DIV column (the visual flow will be CSS)
As Lazers's example is now you're constructing Rows and then breaking it into columns, leaving the sort order across and then down.
Sorry if I missed something.
-K
You'd better go and use a jQuery plugin to make some columns from a list.
Columnizer works very well for me
Here are some django template filter that split a list into multiple sub-lists:
list partition template filters at djangosnippets.org
You could use these in a django template to split a long list into multiple columns as follows:
{% load list_tags %}
<h2>Some List</h2>
{% for sub_list in full_list|rows:"3" %}
<ul>
{% for item in sub_list %}
<li>
{{item.name}}
</li>
{% endfor %}
</ul>
{% endfor %}
I included the template filters in my project in a file called list_tags.py. Adjust the {% load %} tag as necessary.