-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from luftdaten-at/add-endoint-city-current
Add endoint city current
- Loading branch information
Showing
14 changed files
with
371 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
"""add tz to City | ||
Revision ID: 2dcba7bf5523 | ||
Revises: a44ff1a4c716 | ||
Create Date: 2024-10-05 17:47:44.650879 | ||
""" | ||
from typing import Sequence, Union | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
|
||
|
||
# revision identifiers, used by Alembic. | ||
revision: str = '2dcba7bf5523' | ||
down_revision: Union[str, None] = 'a44ff1a4c716' | ||
branch_labels: Union[str, Sequence[str], None] = None | ||
depends_on: Union[str, Sequence[str], None] = None | ||
|
||
|
||
def upgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.add_column('cities', sa.Column('tz', sa.String(), nullable=True)) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_column('cities', 'tz') | ||
# ### end Alembic commands ### |
36 changes: 36 additions & 0 deletions
36
code/alembic/versions/a44ff1a4c716_add_slug_to_city_and_country.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"""add slug to City and Country | ||
Revision ID: a44ff1a4c716 | ||
Revises: dab145493248 | ||
Create Date: 2024-10-05 15:55:11.117312 | ||
""" | ||
from typing import Sequence, Union | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
|
||
|
||
# revision identifiers, used by Alembic. | ||
revision: str = 'a44ff1a4c716' | ||
down_revision: Union[str, None] = 'dab145493248' | ||
branch_labels: Union[str, Sequence[str], None] = None | ||
depends_on: Union[str, Sequence[str], None] = None | ||
|
||
|
||
def upgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.add_column('cities', sa.Column('slug', sa.String(), nullable=True)) | ||
op.create_index(op.f('ix_cities_slug'), 'cities', ['slug'], unique=True) | ||
op.add_column('countries', sa.Column('slug', sa.String(), nullable=True)) | ||
op.create_index(op.f('ix_countries_slug'), 'countries', ['slug'], unique=True) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_index(op.f('ix_countries_slug'), table_name='countries') | ||
op.drop_column('countries', 'slug') | ||
op.drop_index(op.f('ix_cities_slug'), table_name='cities') | ||
op.drop_column('cities', 'slug') | ||
# ### end Alembic commands ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,96 @@ | ||
from fastapi import APIRouter, Depends, Response, HTTPException | ||
from fastapi import APIRouter, Depends, HTTPException, Query | ||
from sqlalchemy.orm import Session | ||
from datetime import datetime, timedelta | ||
from zoneinfo import ZoneInfo | ||
from database import get_db | ||
from models import Station, Measurement, Values | ||
from schemas import StationDataCreate, SensorsCreate | ||
from utils import get_or_create_location, download_csv | ||
import json | ||
from sqlalchemy import func, desc | ||
from datetime import datetime | ||
|
||
from models import City, Country, Station, Measurement, Values | ||
from enums import Dimension | ||
|
||
|
||
router = APIRouter() | ||
|
||
|
||
# @router.get("/v1/city/current/", response_class=Response) | ||
# async def get_current_station_data( | ||
# city: str = None | ||
# ): | ||
# data = "" | ||
# return Response(content=data, media_type="application/json") | ||
@router.get("/all") | ||
async def get_all_cities(db: Session = Depends(get_db)): | ||
# Abfrage aller Städte in der Datenbank | ||
cities = db.query(City, Country).join(Country, City.country_id == Country.id).all() | ||
|
||
if not cities: | ||
raise HTTPException(status_code=404, detail="No cities found") | ||
|
||
response = { | ||
"cities": [ | ||
{ | ||
"id": city.id, | ||
"name": city.name, | ||
"slug": city.slug, | ||
"country": { | ||
"name": country.name, | ||
"slug": country.slug | ||
} | ||
} | ||
for city, country in cities | ||
] | ||
} | ||
return response | ||
|
||
|
||
@router.get("/current") | ||
async def get_average_measurements_by_city( | ||
city_slug: str = Query(..., description="The name of the city to get the average measurements for."), | ||
db: Session = Depends(get_db) | ||
): | ||
# Suche die Stadt in der Datenbank | ||
city = db.query(City).filter(City.slug == city_slug).first() | ||
|
||
if not city: | ||
raise HTTPException(status_code=404, detail="City not found") | ||
|
||
# Finde alle Stationen, die mit dieser Stadt verknüpft sind | ||
stations = db.query(Station).filter(Station.location.has(city_id=city.id)).all() | ||
|
||
if not stations: | ||
raise HTTPException(status_code=404, detail="No stations found in this city") | ||
|
||
# Erstelle eine Liste, um die letzten Messwerte jeder Station zu speichern | ||
last_measurements = [] | ||
|
||
for station in stations: | ||
# Finde die letzte Messung für die Station (nach time_measured) | ||
last_measurement = db.query(Measurement).filter( | ||
Measurement.station_id == station.id | ||
).order_by(desc(Measurement.time_measured)).first() | ||
|
||
if last_measurement: | ||
# Füge alle Werte (dimension, value) der letzten Messung hinzu | ||
values = db.query(Values).filter(Values.measurement_id == last_measurement.id).all() | ||
last_measurements.extend(values) | ||
|
||
if not last_measurements: | ||
raise HTTPException(status_code=404, detail="No measurements found for stations in this city") | ||
|
||
# Berechne den Durchschnitt der letzten Messwerte pro Dimension | ||
avg_measurements = db.query( | ||
Values.dimension, | ||
func.avg(Values.value).label("avg_value") | ||
).filter(Values.id.in_([value.id for value in last_measurements]))\ | ||
.group_by(Values.dimension)\ | ||
.all() | ||
|
||
# Bereite die Antwort im GeoJSON-Format vor | ||
response = { | ||
"city": city.name, | ||
"time": datetime.now(city.tz).isoformat(), | ||
"values": [ | ||
{ | ||
"dimension": dimension, | ||
"name": Dimension.get_name(dimension), | ||
"average": avg_value, | ||
"unit": Dimension.get_unit(dimension) | ||
} | ||
for dimension, avg_value in avg_measurements | ||
] | ||
} | ||
|
||
return response |
Oops, something went wrong.