9
9
from django .conf import settings
10
10
from django .utils import timezone
11
11
from django .db import connection
12
- from django .db .models import ExpressionWrapper , F , FloatField , Max , Min , Sum , Avg , Q , Count
12
+ from django .db .models import ExpressionWrapper , F , FloatField , Max , Min , Sum , Avg , Q , Count , Prefetch
13
13
from django .db .models .functions import Cast , TruncHour , TruncDay , TruncMonth
14
14
from django .utils .decorators import method_decorator
15
15
from django .utils .text import slugify
@@ -134,31 +134,44 @@ class NodesView(viewsets.ViewSet):
134
134
authentication_classes = [SessionAuthentication , TokenAuthentication ]
135
135
permission_classes = [IsAuthenticated ]
136
136
137
- @action (detail = False , methods = ["get" ], url_path = "list-nodes" , url_name = "list_nodes" )
137
+ # Note: Allow access to list_nodes for https://v2.map.aq.sensors.africa/#4/-4.46/19.54
138
+ @action (detail = False , methods = ["get" ], url_path = "list-nodes" , url_name = "list_nodes" , permission_classes = [AllowAny ])
138
139
def list_nodes (self , request ):
139
140
"""List all public nodes with active sensors."""
141
+ now = datetime .datetime .now ()
142
+ one_year_ago = now - datetime .timedelta (days = 365 )
143
+
144
+ last_active_nodes = (
145
+ LastActiveNodes .objects .filter (last_data_received_at__gte = one_year_ago )
146
+ .select_related ("node" , "location" )
147
+ .prefetch_related (
148
+ Prefetch (
149
+ "node__sensors" ,
150
+ queryset = Sensor .objects .filter (public = True ),
151
+ )
152
+ )
153
+ )
154
+
140
155
nodes = []
156
+
141
157
# Loop through the last active nodes
142
- for last_active in LastActiveNodes . objects . iterator () :
158
+ for last_active in last_active_nodes :
143
159
# Get the current node only if it has public sensors
144
- node = Node .objects .filter (
145
- Q (id = last_active .node .id ), Q (sensors__public = True )
146
- ).first ()
147
- if node is None :
160
+ node = last_active .node
161
+ if not node .sensors .exists ():
148
162
continue
149
163
150
164
# The last acive date
151
165
last_data_received_at = last_active .last_data_received_at
152
166
153
167
# last_data_received_at
154
168
stats = []
155
- moved_to = None
156
169
# Get data stats from 5mins before last_data_received_at
157
170
if last_data_received_at :
158
171
last_5_mins = last_data_received_at - datetime .timedelta (minutes = 5 )
159
172
stats = (
160
173
SensorDataValue .objects .filter (
161
- Q (sensordata__sensor__node = last_active . node .id ),
174
+ Q (sensordata__sensor__node = node .id ),
162
175
# Open endpoints should return data from public sensors
163
176
# only in case a node has both public & private sensors
164
177
Q (sensordata__sensor__public = True ),
@@ -170,7 +183,6 @@ def list_nodes(self, request):
170
183
# Match only valid float text
171
184
Q (value__regex = r"^\-?\d+(\.?\d+)?$" ),
172
185
)
173
- .order_by ()
174
186
.values ("value_type" )
175
187
.annotate (
176
188
sensor_id = F ("sensordata__sensor__id" ),
@@ -184,6 +196,7 @@ def list_nodes(self, request):
184
196
185
197
# If the last_active node location is not same as current node location
186
198
# then the node has moved locations since it was last active
199
+ moved_to = None
187
200
if last_active .location .id != node .location .id :
188
201
moved_to = {
189
202
"name" : node .location .location ,
0 commit comments