I want to print to get the details of different cities weather and I had written the code as below. While retreving the data I am not able to fetch the data to HTML.
views.py
from django.shortcuts import render
# Create your views here.
import urllib.request
import json
import requests
def display(request):
city=['vijayawada','guntur','tenali','rajahmundry','amaravathi']
for i in city:
source = urllib.request.urlopen(
'https://api.openweathermap.org/data/2.5/weather?q=' i '&units=metric&appid=5980455dc827c861d5ac4125c3673b43').read()
list_of_data = json.loads(source)
data = {
"country_code": str(list_of_data['sys']['country']),
"coordinate": str(list_of_data['coord']['lon']) ', '
str(list_of_data['coord']['lat']),
"temp": str(list_of_data['main']['temp']) ' °C',
"pressure": str(list_of_data['main']['pressure']),
"humidity": str(list_of_data['main']['humidity']),
'main': str(list_of_data['weather'][0]['main']),
'description': str(list_of_data['weather'][0]['description']),
'icon': list_of_data['weather'][0]['icon'],
}
print(data)
return render(request, "display.html",data)
display.html
<html>
<head>
<title>API Display</title>
</head>
<body>
<h1>Weather details</h1>
<form>
{% for i in data %}
{{ country_code }}
{{ temp }}
{{ i }}
{% endfor %}
</form>
</body>
</html>
I am trying to print the values of the dictionary to html but not getting printed. The values are printing correctly in the console which means the for loop in views.py is working correctly. Please tell me where I am wrong
CodePudding user response:
You might want to make a function that handles the request for each city:
def get_city_weather(city_name):
source = urllib.request.urlopen(
'https://api.openweathermap.org/data/2.5/weather?q=' city_name '&units=metric&appid=5980455dc827c861d5ac4125c3673b43').read()
list_of_data = json.loads(source)
return {
"country_code": str(list_of_data['sys']['country']),
"coordinate": str(list_of_data['coord']['lon']) ', '
str(list_of_data['coord']['lat']),
"temp": str(list_of_data['main']['temp']) ' °C',
"pressure": str(list_of_data['main']['pressure']),
"humidity": str(list_of_data['main']['humidity']),
'main': str(list_of_data['weather'][0]['main']),
'description': str(list_of_data['weather'][0]['description']),
'icon': list_of_data['weather'][0]['icon'],
}
Then use dict comprehension to compile the data
dict to send to the template:
def display(request):
cities=['vijayawada','guntur','tenali','rajahmundry','amaravathi']
data = {city_name: get_city_weather(city_name) for city_name in cities}
return render(request, "display.html", data)
At this point data
is a dictionary who's key is the city name and who's value is the dictionary returned by get_city_weather
, so it looks like (abbreviated):
{'vijayawada':
{'country_code': 'ABC'
# ...
}
# ...
}
Then in the template you could loop through this like:
{% for city_name, city_weather in data.items %}
The temperature in {{city_name}} is {{city_weather.temp}}
and the air pressure is {{city_weather.pressure}}.
{% endfor %}
Or if you don't want to specify the keys like temp
and pressure
, you could do:
{% for city_name, city_weather in data.items %}
<p>Weather data for {{city_name}}:</p>
<ul>
{% for k,v in city_weather.items %}
<li>{{k}}: {{v}}</li>
{% endfor %}
</ul>
<hr />
{% endfor %}
CodePudding user response:
That is because you are overwriting your data dictionary. It's being passed only as one object, it should render something if you try {{data}}
or {{data.country_code}}
, {{data.temp}}
...
One way to solve this, is to have a nested dictionary with the data of every city:
views.py
def loop_dict(request):
cities=['vijayawada','guntur','tenali','rajahmundry','amaravathi']
data = {}
for city in cities:
source = urllib.request.urlopen(
'https://api.openweathermap.org/data/2.5/weather?q=' city '&units=metric&appid=5980455dc827c861d5ac4125c3673b43').read()
list_of_data = json.loads(source)
data[city] = {
"country_code": str(list_of_data['sys']['country']),
"coordinates": {
'latitude': str(list_of_data['coord']['lat']),
'longitude': str(list_of_data['coord']['lon'])
},
"temp": str(list_of_data['main']['temp']) ' °C',
"pressure": str(list_of_data['main']['pressure']),
"humidity": str(list_of_data['main']['humidity']),
'main': str(list_of_data['weather'][0]['main']),
'description': str(list_of_data['weather'][0]['description']),
'icon': list_of_data['weather'][0]['icon'],
}
context = {'data': data}
return render(request, 'loop_dict.html', context)
loop_dict.html:
{% extends 'base.html' %}
{% block content %}
{% for key, obj in data.items %}
<h2>City: {{key}}</h2><br>
<p>Country Code: {{obj.country_code}}</p><br>
<p>Latitude: {{obj.coordinates.latitude}}</p><br>
<p>Longitude: {{obj.coordinates.longitude}}</p><br>
<p>Temp: {{obj.temp}}</p><br>
<hr>
{% endfor %}
{% endblock %}
CodePudding user response:
AFAIK, django template system recognizes dict variable just like Python itself does.
So, if we try to convert your template code back to Python code, we would get something like this:
for i in data:
print(country_code)
print(temp)
print(i)
Now, ask yourself: will it work?
Obviously, it's not.
So, how exactly in Python you would loop and access dict values?
You can do it like this:
for i in data:
print(i)
Or with k,v
loop variables (better way):
for k, v in enumerate(data):
print(f"key: {k}, value: {v}")
But, in your template code, you are trying to access certain values with the key (country_code
etc).
In this case, you probably don't even need to use the for-loop.
And your display.html
file can be rewritten like this:
<html>
<head>
<title>API Display</title>
</head>
<body>
<h1>Weather details</h1>
<form>
{{ data.country_code }}
{{ data.temp }}
</form>
</body>
</html>
Also, as I can see your view retrieves this data
for each given city.
Thought you only pass the last one to your template.
In order to fix this, you must rewrite your view code.
I guess you could add a new variable called collected_data
and then at the end of every data retrieve loop just append data
to this new variable.
After that, you could just pass the collected_data
to the template.
And then loop through it within the template.
But I exactly don't know how your template should look like, so I leave it to you.
I've tried to explain what's the issue is.