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 %}
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)
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"]})
Couple of things:
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
#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 %}
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"))
Related
I need to use data as JSON from an API in Django View here is my JSON data;
[{'Count': 5491}]
I need to pass just value of the "Count" key to HTML and views.py is as below;
def serviceReport(request):
data = mb.post('/api/card/423/query/json')
context = {
'count' : data['Count']
}
return render(request, 'service_report.html', context)
I get error like this;
Exception Type: TypeError
Exception Value:
list indices must be integers or slices, not str
What I want is to pass value of count key to service_report.html and also I want to pass multiple JSON datas like data2, data3 as data on views.py how can I do it?
The json is returning a list that contains a dict.
[{'Count': 5491}]
The brackets are the list so access that with data[0]
def serviceReport(request):
data = mb.post('/api/card/423/query/json')
context = {
'count' : data[0]['Count']
}
return render(request, 'service_report.html', context)
Views.py:
def serviceReport(request):
data = mb.post('/api/card/423/query/json')
context = {
'data' : data
}
return render(request, 'service_report.html', context)
html template:
In Django you can use {% %} to use Python code into html,
so you can do something like this.
<div>
{% for element in data %}
<div>{{element.data}}</div>
{% endfor %}
</div>
Also if you want to check what's on your data, you could just use {{data}}
In anycase, i suggest you do a for in your views.py to append just the "Count" data into a list and then pass that list to the context.
I'm having a problem with accessing the response data from my http request. I'm able to get it if I pass the response through to my html and then take the specific data I want out of it but if I try to take that same part of the response in my python file and pass that through to my html it says "there is no books attribute in the dict".
my html
{% extends "layout.html" %}
{% block heading %}
Search Page
{% endblock %}
{% block body %}
the result of the http request:
<p> {{res}} </p>
I want to add this info from the request
<p>{{res.books[0].average_rating}}
{{res.books[0].work_ratings_count}}</p>
to this dictionary
{{apiDict}}
but the when I use the same syntax to access the average rating and ratings count
from
'res' in my python file it says the respose has no book object, why does this
happen?
{% endblock %}
Here is my python/flask code:
#app.route("/api/<isbn>", methods=["GET"])
def apiacc(isbn):
res = requests.get("https://www.goodreads.com/book/review_counts.json", params=.
{"key": "lzhHXUd9kUpum244vufV2Q", "isbns": isbn}).json()
# avg = res.books[0].average_rating
# rc = res.books[0].work_ratings_count
book = db.execute("SELECT * FROM books WHERE isbn = :i", {"i": isbn}).fetchone()
db.commit()
apiDict = {
"title": book.title,
"author": book.author,
"year": book.year,
"isbn": isbn
}
# apiDict["average_score"] = res.books[0].average_rating
# apiDict["review_count"] = res.books[0].work_ratings_count
return render_template("api.html", res = res, apiDict=apiDict)
I would like to have the python code like this:
apiDict = {
"title": book.title,
"author": book.author,
"year": book.year,
"isbn": isbn,
"average_score": avg,
"review_count": rc
}
and just pass in the apiDict to api.hmtl as the only value but I get the error I mentioned earlier.enter image description here
The res returned by requests will be a dict. In the template, Jinja support to get the dict value with the dot operator, like:
{{ res.books }}
But in Python, you have to use the bracket operator to get the value in a dict (dot operator used to get the attribute):
data = res['books']
I'm passing a bunch of data into my template but am having a hard time breaking apart a zipped list of items. No matter what I try, I always get the following error.
Need 2 values to unpack in for loop; got 0.
Heres my code:
views.py
import requests
from django.shortcuts import render
from django.http import HttpResponse
dictionary, words = [[], []], []
def home(request, username='johnny'):
template_name = 'main/index.html'
url = "https://www.duolingo.com/users/{}".format(username)
getUserData(url)
context = {
'username': username,
'dictionary': dictionary,
'words': words,
}
# print(context)
return render(request, template_name, context)
def getUserData(url):
response = requests.get(url)
userdata = response.json()
wordlists, explanations = [], []
for language in userdata['language_data']:
for index in userdata['language_data'][language]['skills']:
if index.get('levels_finished') > 0:
wordList = index.get("words")
wordlists.append(wordList)
explanations.append(index.get("explanation"))
for wordItem in wordList:
words.append(wordItem)
dictionary = list(zip(wordlists, explanations))
relevant template
{% block content %}
{% for words, exp in dictionary %}
{{ words }}
{{ exp|safe }}
{% endfor %}
{% endblock %}
I've tested this code, it works.
Once I refactored in Django to put wordLists in an array with explanations, things go to hell. If I print(dictionary) at the end of the method, the data shows in the console. Not sure what else I'm missing.
Your problem is with scope. the dictionary(variable) which you are returning from home function(as context) and dictionary in getUserData function are not in same scope. So whenever you are updating getUserData method's dictionary, its not being updated in home. I would not recommend your approach for dictionary as its using global variable. I would recommend something like this:
def getUserData(url):
response = requests.get(url)
userdata = response.json()
wordlists, explanations, words = [], [], []
for language in userdata['language_data']:
for index in userdata['language_data'][language]['skills']:
if index.get('levels_finished') > 0:
wordList = index.get("words")
wordlists.append(wordList)
explanations.append(index.get("explanation"))
for wordItem in wordList:
words.append(wordItem)
return list(zip(wordlists, explanations)), words # return the value of dictionary from here
def home(request, username='johnny'):
template_name = 'main/index.html'
url = "https://www.duolingo.com/users/{}".format(username)
dictionary, words = getUserData(url) # catch value of dictionary
context = {
'username': username,
'dictionary': dictionary,
'words': words,
}
# print(context)
return render(request, template_name, context)
i am trying to get nearby places using googleplaces with python and flask
i am getting this error: (UnboundLocalError: local variable 'place_name' referenced before assignment)
here is my code:
#app.route('/Search', methods=['POST', 'GET'])
#login_required
def Search():
if request.method == 'POST':
query_result = google_places.nearby_search(
lat_lng={'lat':31.7917, 'lng' : 7.0926},
radius=500,
types=[types.TYPE_SHOPPING_MALL] or [types.TYPE_STORE])`
if query_result.has_attributions:
print(query_result.html_attributions)
for place in query_result.places:
place.get_details()
place_name = place.name
print(place.name)
place_rating = place.rating
print(place.rating)
place_location = place.get_location
print(place.get_location)
for photo in place.photos:
photo.get(maxheight=500, maxwidth=500)
photo.mimetype
photo.url
photo.filename
photo.data
return render_template('Search.html', place_name, place_rating, place_location)
else:
return render_template('Search.html')```
#Note: i am new to python in general
return render_template('Search.html', place_name, place_rating, place_location)
The above isn't valid syntax. When you pass the details to the template, you need to do it as:
return render_template('Search.html', name = place_name,
rating = place_rating, location = place_location)
The variables name, rating and location will then be accessible in the template as {{name}}, {{rating}} and {{location}}.
However, the way you have the for loops laid out means the first time the return statement is reached, it will stop the loop and return the template with these variables.
Perhaps this is what you want, but you may wish to pass query_result to the template, and implement a Jinja2 for loop in the template to print out the various place details. You would remove the for loops and replace that whole block with:
return render_template('Search.html', all_places = query_result)
Then in the template something like:
{% if all_places %}
{% for place in all_places %}
<p><b>{{place.name}}</b> has a rating of <u>{{place.rating}}</u></p>
{% endfor %}
{% else %}
<p>No places found.</p>
{% endif %}
I have a Python/Flask app that gathers data from third-party APIs and stores them in a JSON-like structure (nested Python dictionaries called 'results').
I'm sending this to my template using:
def format_results():
item_data = {'name':name, 'age':age, 'address':address}
results = {'title':item_title, 'item_data':item_data}
return jsonify(results)
#app.route('/')
def display_results():
data = format_results()
return render_template('index.html', data = data)
I would like to use d3.js in my template to plot the results on a graph.
What's the recommended way for doing so? (disclaimer: this is my first time using D3.js)
Figured out a way to make this work!
def format_results():
item_data = {'name':name, 'age':age, 'address':address}
results = {'title':item_title, 'item_data':item_data}
return results
#app.route('/')
def display_results():
data = format_results()
return render_template('index.html', data = data)
Removed 'jsonify' and disabled escaping for {{data}}
de = {% autoescape false %} {{data}} {% endautoescape %}