1

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 class="octicon octicon-graph" 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 class="octicon octicon-graph" 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>

2 Answers 2

1

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 class="octicon octicon-graph" 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>
Sign up to request clarification or add additional context in comments.

7 Comments

and should i pass it in place of context when i call the render() ?
Like this ? mylist = map(None, urls, clicks) return render(request, 'heyurl/index.html', mylist)
No, It should be fine placing it inside context
Did that, does not work.
in views.py mylist = map(None, urls, clicks) context = {'mylist': mylist} return render(request, 'heyurl/index.html', context) and then in template i used {% for url in mylist %}
|
1

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 class="octicon octicon-graph" 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!

3 Comments

I made changes as you explained, but after running the server i don't see anything in the table which tells me something is wrong.
weird.. do you have Click objects created?- also make sure you are doing Url.objects.all().order_by('-created_at') I just noticed that (also I missed the i.url in the link column)
It seems there's something wrong. It still does not work

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.