4

I believe this one will be very basic. I am trying to show the number of values in a dictionary on a template. Here is my method for the template route:

# url: localhost/books/home/
def books_home(request):
    if request.method == "GET":
        first_name = User.objects.get(id=request.session['uid']).first_name
        last_name = User.objects.get(id=request.session['uid']).last_name
        email = User.objects.get(id=request.session['uid']).email
        user_id = User.objects.get(id=request.session['uid']).id
        reviews = Review.objects.filter(created_by=request.session['uid']).order_by("-created_at")[:3]
        context = {
            'first_name' : first_name, 
            'email' : email,
            'last_name' : last_name,
            'reviews' : reviews,
            }
        return render(request, 'html_files/home.html', context=context)

Then the pertinent code in the template:

<div class="container">
        <div class="card">
            <h3>Information for {{ first_name }} {{ last_name }}</h3>
            <p>email: {{ email }} </p>
            <p>Number of reviews: {{ len(reviews) }}</p>
        </div>
        <div class="card">
            <h3>Your recent reviews:</h3>
            {% for review in reviews %}
                <p>Review for: <a href="/books/book/{{ review.book.id }}/">{{ review.book.title}}</a> by {{ review.book.author.first_name }} {{ review.book.author.last_name }} <br><br>
                Your review: {{ review.comments }} <br><br>
                Your rating: {{ review.rating }} out of 5</p><br><br><br>
            {% endfor %}
        </div>

I thought that {{ len(reviews }} would do it, since as you can see below, "reviews" has been successfully passed to the context dict. But I am getting a "could not parse remainder" error. Your help is appreciated.

MarianD
  • 13,096
  • 12
  • 42
  • 54
garreth
  • 121
  • 5
  • 8

2 Answers2

10

The tutorial and documentation are explicit that Django template syntax doesn't support calling functions with arguments.

In this case, you can use the length filter:

{{ reviews|length }}

Alternatively, since reviews is a queryset (not a dict), you could call its count method:

{{ reviews.count }}
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
0

First of all you need to have consider about the line you wrote in your question as below:

reviews = Review.objects.filter(created_by=request.session['uid']).order_by("-created_at")[:3]

as you are using slicing in query you can at max get first 3 values.

In your template you may use filter reviews|length as suggested in comment by @kartheek that length is nothing but a template tag included by default in django and you may create your own template tag too.

However for rarely use calculation you can pass another context too and your final context dict would be like below:

context = {
            'first_name' : first_name, 
            'email' : email,
            'last_name' : last_name,
            'reviews' : reviews,
            'total_reviews': len(reviews)
            }

Note: you might found below reference link helpful related to your task:

  1. https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/
  2. https://docs.djangoproject.com/en/2.1/ref/templates/builtins/
Gahan
  • 4,075
  • 4
  • 24
  • 44
  • Gahan, thank you for pointing this out. I actually figured this one out myself (a minor miracle). Over in views, I simply declared a new var, reviews_tot, where I stored all reviews my the active user, rather than only the top 3! – garreth Aug 09 '18 at 16:01
  • you can consider upvoting and/or any helpful answer to you – Gahan Aug 09 '18 at 16:09