Home > Software design >  getting error in printing the dictionary values to html
getting error in printing the dictionary values to html

Time:12-08

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.

  • Related