4

I want to create a list in HTML of locations from JSON API url in python.

@app.route('/api')
def api():
url = urlopen('https://api.openaq.org/v1/locations?country=GB').read()
#encoded we do not need it
#encoded_data = json.dumps(url)

#create variables
array = []
data = {}

#decoded
decoded_data = json.loads(url)

#we search for result each entry
for i in decoded_data["results"]:
    #append every entry to an array
    array.append(i["location"])
#we create a dictionary from that array created which has a variable (for jinja2) called location
data = [dict(location=array)]
return render_template('api.html', data=data)

But instead of receiving each element, I get this:

[u'Aberdeen', u'Aberdeen Union Street Roadside', u'Aberdeen Wellington Road', u'Armagh Roadside', u'Aston Hill', u'Auchencorth Moss', u'Ballymena Ballykeel', u'Barnsley Gawber', u'Barnstaple A39', u'Bath Roadside', u'Belfast Centre', u"Belfast Stockman's Lane", u'Billingham', u'Birkenhead Borough Road', u'Birmingham A4540 Roads...

Edit: Template

 {% if data %}
    <ul>
    {% for d in data %}
      <li>{{ d.location }}</li>
    {% endfor %}
    </ul>
  {% else %}
    <p class="lead">
      You should not see this msg, otherwise, check the code again.
    </p>
  {% endif %}
2
  • Could you show how you are trying to use the data in your template? Commented Nov 17, 2016 at 19:20
  • I just edit it @c3st7n Commented Nov 17, 2016 at 19:25

4 Answers 4

4

I broke my answer down a bit because I didn't want to activate flask.

import requests

def api():
    res = requests.get('https://api.openaq.org/v1/locations?country=GB')
    data = res.json()['results']
    return data


@app.route('/api')
def api():
    res = requests.get('https://api.openaq.org/v1/locations?country=GB')
    try:
        data = res.json()['results']
    except KeyError:
        data = None
    # this is the logic that you use in your template, I moved it out here
    # cause i don't want to start a flask instance
    for d in data:
        print d['location']
    return render_template('api.html', data=data)

api()

Basically I use the requests module which can return a json. I pass the results to the data varible. I used a for loop to demo how it would work in your template. Basically pass in the data as a dictionary and get the location via iteration d['location']

So the code to use is

import requests

@app.route('/api')
def api():
    res = requests.get('https://api.openaq.org/v1/locations?country=GB')
    try:
        data = res.json()['results']
    except KeyError:
        data = None
    return render_template('api.html', data=data)
Sign up to request clarification or add additional context in comments.

2 Comments

I will try this option too but its a bit more complicate to understand
@AdriánVázquez I don't see how its more complex. It uses fewer lines then your example, with less conversations and zero list building. I'll update my example to just contain the code that is copy and paste ready.
2

You are converting the array to a dict, but then you are putting the dict inside an array of length 1, with the only object being the dict. The issue is, your template is then expecting each element in the array to be a dictionary, with a "location" field.

You either can remove the square brackets from the conversion data = dict(location=array) and then update your template to just do for d in data.location, or you can update your append call to append a dictionary item instead of a string: array.append({"location": i["location"]})

2 Comments

It works! but just the first one, I could not make it work the second one, thank you very much!
the second one you would just pass in the array as the data object. The array would essentially be a list of dictionaries so the template would iterate over each dictionary and then select the location field.
1

Couple of things:

  1. url is a bytes object, which will not work with json.loads(str). So you'll have to convert it to a string either by doing json.loads(str(url,'utf-8')) or the method suggested by @Mattia

  2. @louhoula is correct. But, in case you are expecting data to be a list of dictionaries each containing a location key (that's the idea I get by looking at your template), then you should change d.location in your template to :

    {% if 'location' in d.keys(): %}

    {{ d['location'] }}
    

    {% else %} <p class="lead"> You should not see this msg, otherwise, check the code again. </p>

    {% endif %}

Comments

0

Try this:

    import urllib.request, json
    url = 'https://api.openaq.org/v1/locations?country=GB'
    response = urllib.request.urlopen(url);
    decoded_data = json.loads(response.read().decode("utf-8"))

Comments

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.