Python / Django / Jinja2: How to extend a variable name with the value of another variable (e.g. in a for-loop)?

Viewed 52

In my django db model I have e.g. 5x ImageField, which I want to use for a carousel in the front end:

slider_image_1 = models.ImageField(upload_to='images/', blank=True)
slider_image_2 = models.ImageField(upload_to='images/', blank=True)
slider_image_3 = models.ImageField(upload_to='images/', blank=True)
slider_image_4 = models.ImageField(upload_to='images/', blank=True)
slider_image_5 = models.ImageField(upload_to='images/', blank=True)

Depending whether the images were uploaded or not, I want to display the images and I am looking for an approach similar to something like this:

{% for FOO in range(5) %}
    {% if object.slider_image_|extend_name_with:FOO %}
        <img src="{{ object.slider_image_|extend_name_with:FOO.url }}">
    {% endif %}
{% endfor %}

Is something similar possible? What are other good approaches for this problem?

1 Answers

The recommended approach for complex logic in templates is to write the logic in a model method, rather than in the template itself.

In your case, I think this is what you want:

class SomeModel(models.Model):
    slider_image_1 = models.ImageField(upload_to='images/', blank=True)
    slider_image_2 = models.ImageField(upload_to='images/', blank=True)
    slider_image_3 = models.ImageField(upload_to='images/', blank=True)
    slider_image_4 = models.ImageField(upload_to='images/', blank=True)
    slider_image_5 = models.ImageField(upload_to='images/', blank=True)

    @property
    def slider_images(self):
        fields = [field.name for field in self._meta.get_fields()]
        results = []
        for field in fields:
            if 'slider_image' in field:
                data = getattr(self, field)
                if data:
                    results.append(data.url)

        return results

    @property
    def slider_images(self): # simplified version
        results = [getattr(self, field.name) for field in self._meta.get_fields() 
        if 'slider_image' in field]
        return [result.url for result in results if result]

Now you can easily access this list in your templates:

{% for url in object.slider_images %}
  <img src="{{ url }}">
{% endfor %}

This is a bit out of scope for this question, but your slider_image fields looks like it should be a single ManyToManyField. Using a M2M here would massively simplify the amount of work you are doing, and would eliminate the need for my solution entirely. I can't really give you a solution using this because you will probably need to change several pieces of logic throughout your code before this will work.

Related