How to display a table of images in Django template system? - python

I'm developing a Django-based site for fun, and wondered if anyone knows how to solve this problem. I want to display images in a table, like a gallery, inside a template. Does anyone know how to do this? I've tried a multidimensional list, but I am getting nowhere.

I believe question is more CSS related than Django.
Are all your images the same size? If yes, just float all of them and let the bounding div break the images. Your template would looks like something like this (ignore the inline CSS!):
<div style="width:400px">
{% for image in image_list%}
<div style="float:left; width:100px; height:100px;">
{{ image.whatever }}
</div>
{% endfor%}
</div>
This would give you a "table" with 4 columns.
If your images have different widths and heights, I would go with something like display:inline-block, this article explains how it works:
http://robertnyman.com/2010/02/24/css-display-inline-block-why-it-rocks-and-why-it-sucks/
Edit If all you want is to convert a list into a table, I guess you can use this template:
{% for image in image_list %}
{% if forloop.first %}
<tr>
{% endif %}
<td>{{ forloop.counter }} - {{ image }}</td>
{% if forloop.last %}
</tr>
{% else %}
{% if forloop.counter|divisibleby:"4" %}
</tr><tr>
{% endif %}
{% endif %}
{% endfor %}
But this code is not tested! I just wrote it :)

Why don't you use a dictionary? Then you could represent points (0,0), (1,1), (0,1) etc with something like this,
mydict = {0: [0, 1, 2],
1: [0, 1, 2],
2: [0, 1, 2]}
where the elements of the list are your image names.
{0: ["image1.jpg", "image2.jpg", "image3.jpg"] .. }
In this case, mydict[0][0] refers to the first element of the first row, and so on.
--
To access a dict in the template (Django Doc), you could use something like,
# (key would be 0, value would be a list [0,1,2,3..]
{% for key, value in mydict.items %}
{% for img in value %}
<img src="{{img}}">
{% endfor %}
{% endfor %}

Do you really need to use table to align your images the way you need? If you need to get something like this http://blog.mozilla.com/webdev/files/2009/02/gallery-view.jpg, please take a look at inline-block CSS property. It is supported by all major browsers including IE6+ (with a little fix).
http://blog.mozilla.com/webdev/2009/02/20/cross-browser-inline-block/

Here's a much much simpler way that what others have answered:
The goal is to create a new row after each 4th image displayed. A 1 dimensional list is all you need.
One option would be to close the after each 4th . You can use the forloop.counter or you can use {% cycle '' '' '' '' %} after you create each tag. Note: I'm speculating a bit about your HTML structure. {% cycle '' '' '' '' %} might do just as fine.
Here is what cycle does: http://docs.djangoproject.com/en/dev/ref/templates/builtins/#cycle
If you're using s floated to the left, use the same cycle but add a line break after each 4th .

Related

TemplateSyntaxError: 'for' statements should use the format 'for x in y' [duplicate]

With this code:
{% for o in [1,2,3] %}
<div class="{% cycle 'row1' 'row2' %}">
{% cycle 'row1' 'row2' %}
</div>
{% endfor %}
I get a TemplateSyntaxError:
Could not parse the remainder: '[1,2,3]' from '[1,2,3]'
Is there a way of building a list in a template?
We can use split method on str object :
page.html :
{% with '1 2 3' as list %}
{% for i in list.split %}
{{ i }}<br>
{% endfor %}
{% endwith %}
Results :
1
2
3
You can do it via cunning use of the make_list filter, but it's probably a bad idea:
{% for o in "123"|make_list %}
<div class="{% cycle 'row1' 'row2' %}">
{% cycle 'row1' 'row2' %}
</div>
{% endfor %}
p.s. You don't seem to be using o anywhere, so I'm not sure what you're trying to do.
I made this template tag to achieve this goal.
from django import template
register = template.Library()
# use #register.assignment_tag
# only when you're working with django version lower than 1.9
#register.simple_tag
def to_list(*args):
return args
to use it in template:
{% load your_template_tag_file %}
{% to_list 1 2 3 4 5 "yes" as my_list %}
{% for i in my_list %}
{{ i }}
{% endfor %}
Reference here:
Django simple tags
The other answers here look like the ticket (at least for what I wanted), so I'll provide an answer as to WHY you might want to do something like this (and perhaps there's a better answer for my case than what's been provided):
I came across this question looking for a way to build 3 very similar, but not identical buttons using Bootstrap. One button might look like
<div class="btn-group">
<a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#">
Modality
<span class="caret"></span>
</a>
<ul class="dropdown-menu" id="Modality">
<li>Action</li>
</ul>
</div>
where the difference between buttons is limited to the text of the button (Modality, on its own line above) and the contents of the pertaining to the button, which we'll assume is filled dynamically by JS (referencing id="Modality").
If I need to make 10 of these, copy/pasting the HTML seems dumb and tedious, especially if I want to change anything about my button after the fact (like making all of them split-drop-downs) and it goes against DRY.
So, instead, in the template I could do something like
{% with 'Modality Otherbutton Thirdbutton' as list %}
{% for i in list.split %}
<!-- copy/paste above code with Modality replaced by {{ i }} -->
{% endfor %}
{% endwith %}
Now, granted, in this particular case the buttons add functionality to some related data grid, so the button names could be dynamically filled from django model-sourced data as well, but I'm not at that stage in my design right now, and you can see where this sort of functionality is desirable to maintain DRY.
The simplest is to do
{% for x in "123" %}
drodger is correct, you can't do that in the deliberately-crippled Django template lanuage. Either pass in the list as a context variable when you invoke the template or try a template tag like expr. Then you can say {% expr [1,2,3] as my_list %} and then use my_list in your for loop.
This maybe an inspiration. Use the buildin filter add.
{{ first|add:second }}
first is [1, 2, 3] and second is [4, 5, 6], then the output will be [1, 2, 3, 4, 5, 6].
This filter will first try to coerce both values to integers.
If this fails, it'll attempt to add the values together anyway.
This will work on some data types (strings, list, etc.) and fail on others.
If it fails, the result will be an empty string.
The official specification,https://docs.djangoproject.com/zh-hans/2.0/ref/templates/builtins/#built-in-filter-reference

slice requires 2 arguments, 1 provided

I'm trying to add some values from another list synchronously in the for loop of django ’s template. When I use a given number everything works fine, but when I replace it to {{forloop.counter}} it reports an error slice requires 2 arguments, 1 provided
I Googled it and the suggestion is that there should be no spaces in the code, but there are no spaces in my code, here the code in question.
{% for i in invtypes %}
<li>
...
<p>{{data|slice:":{{forloop.counter}}"}}</p>
</li>
{% endfor %}
The {{data}} is a list of extra data for invtypes so they have same length and sort。
I added a colon after slice to fix the error.
Before:
{{ post.body|slice":200" }}
After:
{{ post.body|slice:":200" }}
The problem is that in the line {{data|slice:":{{forloop.counter}}"}} the ":{{forloop.counter}}" would not work as you expect as if it were performing string interpolation. What can be done to get around this is to use the with template tag along with the add and stringformat template filters to get the required value as a template variable before you try to render that:
{% for i in invtypes %}
<li>
...
{% with str_counter=forloop.counter|stringformat:"i" %}
{% with slice_var=":"|add:str_counter %}
<p>{{ data|slice:slice_var }}</p>
{% endwith %}
{% endwith %}
</li>
{% endfor %}
One should also note that a need to do this implies that the view is not supplying the data to the template in an efficient manner, ideally the template should not be doing all of this manipulation with data. It can be seen that invtypes and data have some type of relationship but the context given by the view does not convey that at all.
I had the same problem and the solutions seems to be spaces indeed.
Try:
{% for i in invtypes %}
<li>
...
<p>{{ data|slice:":{{ forloop.counter }}" }}</p>
</li>
{% endfor %}
and see how that goes.
I found the correct solution.
(Wrong) =>
{{data|slice: ":{{forloop.counter}}"}}
[don't add a space after slice's colon.
(Right) =>
{{data|slice:":{{forloop.counter}}"}}
If you add a space after slice's colon, it takes only the part which comes before that space and considered it as one argument and second one will be considered as missing.

Is there a way to output just the first element in this if statement, Django template?

In my table and in the some record I have lot of link_img, but I want only the first link_img, what can I do ?
I have something like this in my temp
{% for link in sousimg %}
{% if article.article_img.id == link.img_link.id %}
{{ link.link_img }}
{% endif %}
{% endfor %}
This type of question is already present so I suggest having a look at it.
django for loop counter break
You have to do a little bit of hit and trial in this case.

How to get out some items from an array

In my flask / jinja2 app, I am getting some rows from a database to print in a table. For each row I want to define an identifier for the row from the first item, define the class of the row with the second item and print the rest of the row as table data. I am doing it like this, it works but feels a bit kludgy:
{%- for item in row %}
{% if loop.index==1 %}
<tr id="rec{{item}}"
{% elif loop.index==2 %}
class="{{item}}" >
{% else %}
<td>{{item}}</td>
{% endif %}
{% endfor -%}</tr>
I would like to do something like:
id="rec"+row.pop()
class=row.pop()
then use the variables id and class to define the row and afterwards iterate through what is left of the list. Is this possible in jinja2?
(Using jinja 2.8 as installed on debian 9, but may of course upgrade if that makes things better)
I think you can use slicing in Jinja templates, could you try this, since I can't test it atm:
<tr id="rec{{row[0]}}"
class="{{row[1]}}" >
{% for item in row[2:] %}
<td>{{item}}</td>
{% endfor -%}
</tr>
You could get the first items from the array using their indices and use a slice (e.g. row[2:]) of the array for the for-loop:
<tr id="rec{{row[0]}}" class="{{row[1]}}" >
{%- for item in row[2:] %}
<td>{{item}}</td>
{% endfor -%}</tr>

Can I evaluate expressions in a django template?

I'm trying to display table rows with alternating colors. For that, I have two css classes row1 and row2 that I'd like to assign in an alternating pattern to the rows of a table. Ideally, I'd determine if the row is odd or even based on the forloop.counter variable
This is what I'd like the template to do (invalid code, but I think it's self explaning).
{% for norma in normas %}
{% if forloop.counter %2 != 0 %}
<tr class="row1">
{% else %}
<tr class="row2">
{% endif %}
<td>yadda... yadda</td>
.
.
.
{% endfor %}
Is there a way to do this within django template system?
Use cycle - the example shows this exact purpose
Just use in your {%for%} loop :
<tr class="{% cycle 'row1' 'row2' %}>
django templete will cycle through each row. you can add as many items in the cycle.
the followin post explains how to get alternating row colors in Django.
Alternate Row Coloring in Django Template with More Than One Set of Rows

Categories