Skip to content

Commit 35a9618

Browse files
authored
Merge pull request #114 from luftdaten-at/113-catch-api-error-in-stations-and-cities
113 catch api error in stations and cities
2 parents 289b8df + ba5304e commit 35a9618

File tree

5 files changed

+203
-47
lines changed

5 files changed

+203
-47
lines changed

app/cities/views.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,24 @@ def CitiesDetailView(request, pk):
5050

5151
def CitiesListView(request):
5252
api_url = f"{settings.API_URL}/city/all"
53-
53+
error_message = None
54+
cities = []
55+
5456
try:
5557
# Perform the GET request
5658
response = requests.get(api_url)
5759
response.raise_for_status() # Raise an error for unsuccessful requests
5860
data = response.json() # Parse JSON response
59-
61+
6062
# Extract and sort the list of cities alphabetically by name
6163
cities = data.get("cities", [])
6264
cities = sorted(cities, key=lambda city: city.get("name", "").lower()) # Sort case-insensitively
63-
65+
6466
except requests.exceptions.HTTPError as err:
65-
raise Http404(f"Cities not found.")
67+
# Instead of raising a 404, store an error message to be shown in the template.
68+
error_message = "There was an error fetching the city data: 404."
69+
except requests.exceptions.RequestException as err:
70+
# Catch any other request exceptions that might occur.
71+
error_message = "There was an error fetching the city data."
6672

67-
return render(request, "cities/list.html", {"cities": cities})
73+
return render(request, "cities/list.html", {"cities": cities, "error": error_message})

app/stations/views.py

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import requests
2-
from datetime import datetime, timezone, timedelta
2+
from datetime import datetime, timedelta
33
from collections import defaultdict
4-
from django.shortcuts import render, get_object_or_404
4+
from django.shortcuts import render
55
from django.http import Http404
66
from django.conf import settings
7-
from main.enums import Dimension, SensorModel, OutputFormat, Precision, Order
7+
from main.enums import OutputFormat, Precision, Order
8+
from requests.exceptions import HTTPError, RequestException
9+
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
810

911
def StationDetailView(request, pk):
1012
# Beispiel API-URL, die von der Station-ID abhängt
@@ -61,33 +63,70 @@ def StationDetailView(request, pk):
6163

6264
def StationListView(request):
6365
"""
64-
max_station: List[Tuple[device,time_measured,dimension,value]]
65-
min_stations: List[Tuple[device,time_measured,dimension,value]]
66+
Fetches two lists: stations with the highest PM2.5 values and
67+
stations with the lowest PM2.5 values.
6668
"""
67-
6869
url_min = f"{settings.API_URL}/station/topn?n=10&dimension=3&order={Order.MIN.value}&output_format={OutputFormat.CSV.value}"
6970
url_max = f"{settings.API_URL}/station/topn?n=10&dimension=3&order={Order.MAX.value}&output_format={OutputFormat.CSV.value}"
70-
71-
resp_min = requests.get(url_min)
72-
resp_max = requests.get(url_max)
7371

74-
# TODO: try catch
75-
resp_min.raise_for_status()
76-
resp_max.raise_for_status()
72+
error_message = None
73+
try:
74+
resp_min = requests.get(url_min)
75+
resp_max = requests.get(url_max)
7776

78-
min_stations = [
79-
line.split(",")
80-
for i, line in enumerate(resp_min.text.splitlines())
81-
if i
82-
]
77+
# Raise HTTPError for bad responses
78+
resp_min.raise_for_status()
79+
resp_max.raise_for_status()
8380

84-
max_stations = [
85-
line.split(",")
86-
for i, line in enumerate(resp_max.text.splitlines())
81+
# Skip header line (i == 0)
82+
min_stations = [
83+
line.split(",")
84+
for i, line in enumerate(resp_min.text.splitlines())
8785
if i
88-
]
86+
]
87+
max_stations = [
88+
line.split(",")
89+
for i, line in enumerate(resp_max.text.splitlines())
90+
if i
91+
]
92+
93+
except (HTTPError, RequestException) as e:
94+
# Instead of raising a 404, store an error message in the context.
95+
error_message = "There was an error fetching station data: 404."
96+
# Optionally, you can log the error:
97+
print(f"Error fetching station data: {e}")
98+
min_stations = []
99+
max_stations = []
100+
101+
# Paginate each list separately (example: 5 stations per page)
102+
paginator_top = Paginator(max_stations, 5)
103+
paginator_low = Paginator(min_stations, 5)
104+
105+
page_top = request.GET.get('page_top')
106+
page_low = request.GET.get('page_low')
107+
108+
try:
109+
top_stations_page = paginator_top.page(page_top)
110+
except PageNotAnInteger:
111+
top_stations_page = paginator_top.page(1)
112+
except EmptyPage:
113+
top_stations_page = paginator_top.page(paginator_top.num_pages)
114+
115+
try:
116+
lowest_stations_page = paginator_low.page(page_low)
117+
except PageNotAnInteger:
118+
lowest_stations_page = paginator_low.page(1)
119+
except EmptyPage:
120+
lowest_stations_page = paginator_low.page(paginator_low.num_pages)
121+
122+
context = {
123+
'top_stations': top_stations_page,
124+
'lowest_stations': lowest_stations_page,
125+
'paginator_top': paginator_top,
126+
'paginator_low': paginator_low,
127+
'page_top': top_stations_page,
128+
'page_low': lowest_stations_page,
129+
'error': error_message,
130+
}
89131

90-
return render(request, 'stations/list.html', {
91-
'top_stations': max_stations,
92-
'lowest_stations': min_stations,
93-
})
132+
return render(request, 'stations/list.html', context)

app/templates/cities/list.html

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,25 @@
88
{% endblock styles %}
99

1010
{% block content %}
11-
<h2>{% trans "Cities and municipalities" %}</h2>
12-
<p>
13-
{% for city in cities %}
14-
<a href="/cities/{{ city.slug }}">{{ city.name }}</a> ({{ city.country.name }}){% if not forloop.last %}, {% endif %}
15-
{% endfor %}
16-
</p>
17-
{% endblock content %}
11+
<h2 class="mb-4 mt-5">{% trans "Cities and municipalities" %}</h2>
12+
13+
{% if error %}
14+
<div class="alert alert-danger" role="alert">
15+
{{ error }}
16+
</div>
17+
{% endif %}
18+
19+
{% if cities %}
20+
<p>
21+
{% for city in cities %}
22+
<a href="/cities/{{ city.slug }}">{{ city.name }}</a> ({{ city.country.name }}){% if not forloop.last %}, {% endif %}
23+
{% endfor %}
24+
</p>
25+
{% else %}
26+
{% if not error %}
27+
<div class="alert alert-info" role="alert">
28+
{% trans "No cities available." %}
29+
</div>
30+
{% endif %}
31+
{% endif %}
32+
{% endblock content %}

app/templates/stations/list.html

Lines changed: 105 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,128 @@
3333
{% endblock styles %}
3434

3535
{% block content %}
36-
<h2>{% trans "Stations overview" %}</h2>
36+
<h2 class="mb-4 mt-5">{% trans "Stations overview" %}</h2>
37+
38+
<!-- Display error message if present -->
39+
{% if error %}
40+
<div class="alert alert-danger" role="alert">
41+
{{ error }}
42+
</div>
43+
{% else %}
3744
<div class="row">
38-
<!-- Spalte 1: Stationen mit den höchsten Werten -->
45+
<!-- Column 1: Top 10 with the highest values -->
3946
<div class="col-md-6">
4047
<h3 class="text-center">{% trans "Top 10 with the highest values for PM2.5" %}</h3>
4148
<ul class="list-group">
4249
{% for station in top_stations %}
4350
<li class="list-group-item d-flex justify-content-between align-items-center">
44-
<a href="/stations/{{ station.0 }}" class="station-link">Station {{ station.0 }}</a>
45-
<span class="badge bg-danger rounded-pill">{{ station.3 }} µg/m³</span> <!-- Value -->
51+
<a href="{% url 'station-detail' station.0 %}" class="station-link">
52+
Station {{ station.0 }}
53+
</a>
54+
<span class="badge bg-danger rounded-pill">{{ station.3 }} µg/m³</span>
4655
</li>
4756
{% endfor %}
4857
</ul>
58+
59+
{% if top_stations.has_other_pages %}
60+
<nav aria-label="{% trans 'Top station pagination' %}">
61+
<ul class="pagination justify-content-center mt-2">
62+
{% if top_stations.has_previous %}
63+
<li class="page-item">
64+
<a class="page-link" href="?page_top={{ top_stations.previous_page_number }}" aria-label="{% trans 'Previous' %}">
65+
<span aria-hidden="true">&laquo;</span>
66+
</a>
67+
</li>
68+
{% else %}
69+
<li class="page-item disabled">
70+
<span class="page-link" aria-hidden="true">&laquo;</span>
71+
</li>
72+
{% endif %}
73+
74+
{% for num in paginator_top.page_range %}
75+
{% if top_stations.number == num %}
76+
<li class="page-item active" aria-current="page">
77+
<span class="page-link">{{ num }}</span>
78+
</li>
79+
{% elif num > top_stations.number|add:'-3' and num < top_stations.number|add:'3' %}
80+
<li class="page-item">
81+
<a class="page-link" href="?page_top={{ num }}">{{ num }}</a>
82+
</li>
83+
{% endif %}
84+
{% endfor %}
85+
86+
{% if top_stations.has_next %}
87+
<li class="page-item">
88+
<a class="page-link" href="?page_top={{ top_stations.next_page_number }}" aria-label="{% trans 'Next' %}">
89+
<span aria-hidden="true">&raquo;</span>
90+
</a>
91+
</li>
92+
{% else %}
93+
<li class="page-item disabled">
94+
<span class="page-link" aria-hidden="true">&raquo;</span>
95+
</li>
96+
{% endif %}
97+
</ul>
98+
</nav>
99+
{% endif %}
49100
</div>
50-
<!-- Spalte 2: Stationen mit den niedrigsten Werten -->
101+
102+
<!-- Column 2: Top 10 with the lowest values -->
51103
<div class="col-md-6">
52104
<h3 class="text-center">{% trans "Top 10 with the lowest values for PM2.5" %}</h3>
53105
<ul class="list-group">
54106
{% for station in lowest_stations %}
55107
<li class="list-group-item d-flex justify-content-between align-items-center">
56-
<a href="/stations/{{ station.0 }}" class="station-link">Station {{ station.0 }}</a>
57-
<span class="badge bg-success rounded-pill">{{ station.3 }} µg/m³</span> <!-- Value -->
108+
<a href="{% url 'station-detail' station.0 %}" class="station-link">
109+
Station {{ station.0 }}
110+
</a>
111+
<span class="badge bg-success rounded-pill">{{ station.3 }} µg/m³</span>
58112
</li>
59113
{% endfor %}
60114
</ul>
115+
116+
{% if lowest_stations.has_other_pages %}
117+
<nav aria-label="{% trans 'Lowest station pagination' %}">
118+
<ul class="pagination justify-content-center mt-2">
119+
{% if lowest_stations.has_previous %}
120+
<li class="page-item">
121+
<a class="page-link" href="?page_low={{ lowest_stations.previous_page_number }}" aria-label="{% trans 'Previous' %}">
122+
<span aria-hidden="true">&laquo;</span>
123+
</a>
124+
</li>
125+
{% else %}
126+
<li class="page-item disabled">
127+
<span class="page-link" aria-hidden="true">&laquo;</span>
128+
</li>
129+
{% endif %}
130+
131+
{% for num in paginator_low.page_range %}
132+
{% if lowest_stations.number == num %}
133+
<li class="page-item active" aria-current="page">
134+
<span class="page-link">{{ num }}</span>
135+
</li>
136+
{% elif num > lowest_stations.number|add:'-3' and num < lowest_stations.number|add:'3' %}
137+
<li class="page-item">
138+
<a class="page-link" href="?page_low={{ num }}">{{ num }}</a>
139+
</li>
140+
{% endif %}
141+
{% endfor %}
142+
143+
{% if lowest_stations.has_next %}
144+
<li class="page-item">
145+
<a class="page-link" href="?page_low={{ lowest_stations.next_page_number }}" aria-label="{% trans 'Next' %}">
146+
<span aria-hidden="true">&raquo;</span>
147+
</a>
148+
</li>
149+
{% else %}
150+
<li class="page-item disabled">
151+
<span class="page-link" aria-hidden="true">&raquo;</span>
152+
</li>
153+
{% endif %}
154+
</ul>
155+
</nav>
156+
{% endif %}
61157
</div>
62158
</div>
63-
64-
{% endblock content %}
159+
{% endif %}
160+
{% endblock content %}

app/templates/workshops/list.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{% block title %}{% trans "Workshops" %}{% endblock title %}
66

77
{% block content %}
8-
<h2 class="mb-4">{% trans "Workshops" %}</h2>
8+
<h2 class="mb-4 mt-5">{% trans "Workshops" %}</h2>
99
<p>{% trans "We continuously host workshops where air quality is measured together. On this page, the results of all public workshops are listed." %}</p>
1010

1111
<!-- Laufende Workshops -->

0 commit comments

Comments
 (0)