Home > Mobile >  How to print multiple values from two lists in django template
How to print multiple values from two lists in django template

Time:10-14

I am trying to figure out a way to print values from two different context variables in a single loop. I have tried the zip() method but it does not seem to work and does not print variables on the template.

This is how I tried

index.html

<tbody>
                {% for item1, item2 in mylist %}
                <tr>
                  <td><a href="/{{ url.short_url }}">/{{ item1.short_url }}</a></td>
                  <td>{{ item1.original_url }}</td>
                  <td>{{ item1.created_at }}</td>
                  <td>{{ item1.clicks|intcomma }}</td>
                  <td>{{ item2.browser }}</td>
                  <td>{{ item2.platform }}</td>
                  <td><a href="#">
                      <svg  viewBox="0 0 16 16" version="1.1" width="16" height="16"
                        aria-hidden="true">
                        <path fill-rule="evenodd" d="M16 14v1H0V0h1v14h15zM5 13H3V8h2v5zm4 0H7V3h2v10zm4 0h-2V6h2v7z">
                        </path>
                      </svg>
                    </a></td>
                </tr>
                {% endfor %}
              </tbody>

views.py

def index(request):
    urls = Url.objects.order_by('-created_at')
    clicks = Click.objects.order_by('-created_at')
    # context = {'urls': urls, 'clicks': clicks}
    mylist = zip(urls, clicks)
    context = {
                'mylist': mylist,
            }
    return render(request, 'heyurl/index.html', context)

But on running the local server I don't see anything on the table view.

What am I doing wrong here? Are there any alternatives ?

Here's my current version of code.

models.py

from django.db import models

class Url(models.Model):
    short_url = models.CharField(max_length=255)
    original_url = models.CharField(max_length=255)
    clicks = models.IntegerField(default=0)
    created_at = models.DateTimeField('date created', auto_now_add=True)
    updated_at = models.DateTimeField('date updated', auto_now=True)

class Click(models.Model):
    url = models.ForeignKey(Url, on_delete=models.CASCADE, related_name='related_clicks')
    browser = models.CharField(max_length=255)
    platform = models.CharField(max_length=255)
    created_at = models.DateTimeField('date created', auto_now_add=True)
    updated_at = models.DateTimeField('date updated', auto_now=True)

index.py

def index(request):
    urls = Url.objects.order_by('-created_at')
    clicks = Click.objects.order_by('-created_at')
    context = {'urls': urls, 'clicks': clicks}
    return render(request, 'heyurl/index.html', context)

templates/index.html

                <tbody>
                {% for url in urls %}
                <tr>
                  <td><a href="/{{ url.short_url }}">/{{ url.short_url }}</a></td>
                  <td>{{ url.original_url }}</td>
                  <td>{{ url.created_at }}</td>
                  <td>{{ url.clicks|intcomma }}</td>
                  <td>{{ click.browser }}</td>
                  <td>{{ click.platform }}</td>
                  <td><a href="#">
                      <svg  viewBox="0 0 16 16" version="1.1" width="16" height="16"
                        aria-hidden="true">
                        <path fill-rule="evenodd" d="M16 14v1H0V0h1v14h15zM5 13H3V8h2v5zm4 0H7V3h2v10zm4 0h-2V6h2v7z">
                        </path>
                      </svg>
                    </a></td>
                </tr>
                {% endfor %}
              </tbody>

CodePudding user response:

In views.py :

try using map instead of zip especially if the two lists don't have the same length

mylist = map(None, urls, clicks)

in views.py

def index(request):
    urls = Url.objects.order_by('-created_at')
    clicks = Click.objects.order_by('-created_at')
    mylist = zip(urls, clicks)  # this should be fine but if it doesn't work try mylist= map(None, urls, clicks)
    context = {
                'mylist': mylist,
            }
    return render(request, 'heyurl/index.html', context)

in template/index.html

                <tbody>
                {% for url, click in mylist %}
                <tr>
                  <td><a href="/{{ url.short_url }}">/{{ url.short_url }}</a></td>
                  <td>{{ url.original_url }}</td>
                  <td>{{ url.created_at }}</td>
                  <td>{{ url.clicks|intcomma }}</td>
                  <td>{{ click.browser }}</td>
                  <td>{{ click.platform }}</td>
                  <td><a href="#">
                      <svg  viewBox="0 0 16 16" version="1.1" width="16" height="16"
                        aria-hidden="true">
                        <path fill-rule="evenodd" d="M16 14v1H0V0h1v14h15zM5 13H3V8h2v5zm4 0H7V3h2v10zm4 0h-2V6h2v7z">
                        </path>
                      </svg>
                    </a></td>
                </tr>
                {% endfor %}
              </tbody>

CodePudding user response:

This is an alternative

Just loop through the Click Objects and reach their Url pair through the ForeignKey, It would be a lot easier!

def index(request):
    clicks = Click.objects.all().order_by('-created_at')
    context = {'clicks': clicks}
    return render(request, 'heyurl/index.html', context)
                <tbody>
                {% for i in clicks %}
                <tr>
                  <td><a href="/{{ i.url.short_url }}">/{{ i.url.short_url }}</a></td>
                  <td>{{ i.url.original_url }}</td>
                  <td>{{ i.url.created_at }}</td>
                  <td>{{ i.url.clicks|intcomma }}</td>
                  <td>{{ i.browser }}</td>
                  <td>{{ i.platform }}</td>
                  <td><a href="#">
                      <svg  viewBox="0 0 16 16" version="1.1" width="16" height="16"
                        aria-hidden="true">
                        <path fill-rule="evenodd" d="M16 14v1H0V0h1v14h15zM5 13H3V8h2v5zm4 0H7V3h2v10zm4 0h-2V6h2v7z">
                        </path>
                      </svg>
                    </a></td>
                </tr>
                {% endfor %}
              </tbody>

I say this because the current way you are doing it there is a possibility of one of them is missing and then it gets all sorts of screwed up

# This is just illustrating the point

# Pairs
Click0 - > Url0,
Click1 - > None,
Click2 - > Url2,
Click3 - > Url3,

## Loop Output
Click0 - > Url0,
Click1 - > Url2, # x    :(
Click2 - > Url3, # x    :(
Click3 - > None, # Actually Click3 might not even show!
  • Related