djangotemplates

How to show in django template data from connected models?


I have a models:

class Publication(models.Model):

pub_text = models.TextField(null=True, blank=True)
pub_date = models.DateTimeField(auto_now_add=True)
pub_author = models.ForeignKey(User, on_delete=models.CASCADE)
coor_text = models.CharField(null=True, blank=True)
coor_adress = models.CharField(null=True, blank=True)
coor_coordinates = models.CharField(null=True, blank=True)

class Image(models.Model):

image = models.ImageField(upload_to='images', null=True)
image_to_pub = models.ForeignKey(Publication, on_delete=models.CASCADE, null=True, related_name='images')

And i have view:

def pub_list_view(request):
pubs = Publication.objects.all()
images = Image.objects.all()
context = {"pubs": pubs, "images": images}
return render(request, "epictalk/pub_list.html", context)

And i have template:

{% extends 'epictalk/layout.html' %}

{% block content %}

{% for pub in pubs %}
    <h1>{{ pub.pub_text }}</h1>
    {% for image in images %}
        <img src="{{ image.image.url }}">
    {% endfor %}
{% endfor %}

{% endblock %}

How to show in browser a Publications with a connected images to it? How to show in browser a Publications with a connected frist image to it?


Solution

  • Only pass publications to the template:

    def pub_list_view(request):
        pubs = Publication.objects.prefetch_related('images')
        return render(request, 'epictalk/pub_list.html', {'pubs': pubs})

    and then use the relation in reverse in the template:

    {% for pub in pubs %}
        <h1>{{ pub.pub_text }}</h1>
        {% for image in pub.images.all %}
            <img src="{{ image.image.url }}">
        {% endfor %}
    {% endfor %}

    The .prefetch_related(…) [Django-doc] in the view is strictly speaking not necessary, but it will boost performance, since we fetch all images in one query, not one query per Publication.

    For the first item, we can use:

    {% for pub in pubs %}
        <h1>{{ pub.pub_text }}</h1>
        {% for image in pub.images.all|slice:":1" %}
            <img src="{{ image.image.url }}">
        {% endfor %}
    {% endfor %}