How to define JSON properties to use in a for loop?

Asked

Viewed 44 times

-1

I’m reading a JSON that looks like this: Google Books and trying to display it in HTML. The user’s search input is the seek which is received through the request.form.get down below:

import requests
from flask import Flask, render_template, redirect, request, session

@app.route('/search', methods=["GET", "POST"])
@login_required
def search():
    """Pesquisa um livro utilizando a API do Google Books"""
    if request.method == "POST":
        try:
            seek = request.form.get("seek")
            url = f'https://www.googleapis.com/books/v1/volumes?q={seek}'
            response = requests.get(url)
            response.raise_for_status()
        except requests.RequestException:
            return None
        # Parse response
        try:
            search = response.json()
            search = {
                "totalItems": int(search["totalItems"]),
                "items": search["items"]
            }
            return render_template("search.html", search=search)
        except (KeyError, TypeError, ValueError):
            return None
    else:
        return render_template("index.html")

The search works well, but I still don’t know where I’m going wrong when sending to HTML. I’m trying to display it as follows:

{% for seek in search %}
  <figure>
    <a><img src="{{ seek['items']['imageLinks']['thumbnail'] }}"></a>
    <p>{{ seek["items"]["volumeInfo"]["title"] }}</p>
    <p>{{ seek["items"]["volumeInfo"]["authors"] }}</p>
  </figure>
{% endfor %}

The terminal returns me the following message:

jinja2.exceptions.UndefinedError: 'str object' has no attribute 'items'

Someone would know to tell me what I’m missing?

1 answer

1


Okay, from what I see, the search structure would be something like this:

{
  "kind": "books#volumes",
  "totalItems": 894,
  "items": [{...}, {...}]
}

when you spin your for about the object search, the variable seek will take as value the property of the object ("kind", "totalItems", "items")

So, you are not iterating on the items as you would like

the correct would be

{% for seek in search["items"] %}
  <figure>
    <a><img src="{{ search["items"][seek]['volumeInfo']['imageLinks']['thumbnail'] }}"></a>
    <p>{{ search["items"][seek]["volumeInfo"]["title"] }}</p>
    <p>{{ search["items"][seek]["volumeInfo"]["authors"].join(",") }}</p>
  </figure>
{% endfor %}

Note that authors is also an array, so recommend the join or other form of display

Note also imageLinks this one inside volumeInfo

Another improvement point, is that in javascript, a map is treated as an object, so you don’t need to access the properties like this doing, but like this:

here I am also adding a check to avoid Undefined

{% for seek in search.items %}
  <figure>
    <a><img src="{{ search.items[seek].volumeInfo.imageLinks && search.items[seek].volumeInfo.imageLinks.thumbnail }}"></a>
    <p>{{ search.items[seek].volumeInfo.title }}</p>
    <p>{{ search.items[seek].volumeInfo.imageLinks && search.items[seek].volumeInfo.authors.join(",") }}</p>
  </figure>
{% endfor %}

PS: Seek in this syntax loads the array’s input

PS2: you need to decide what to do when the attribution does not exist

  • Very good your solution Fernando! However, some of the research is returning jinja2.exceptions.UndefinedError: 'dict object' has no attribute 'imageLinks'. By the terms that I’ve been researching, I found that some books do not have thumbnail, you can tell me what would be the exit in this case?

  • 1

    Fixed... Seek in this syntax loads the array’s input

Browser other questions tagged

You are not signed in. Login or sign up in order to post.