From 9fe99f0cde0a66dd37c7de188a90e37f5d68761f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 7 Jul 2025 14:51:10 +0200 Subject: [PATCH] Update main.py and history.html; add new templates --- main.py | 370 ++++++++++++++++++++++++++++++++- main_copy.py | 298 ++++++++++++++++++++++++++ templates/forecast.html | 69 ++++++ templates/history.html | 41 +++- templates/history_range.html | 67 ++++++ templates/hourly_forecast.html | 67 ++++++ templates/ping.html | 11 + templates/test.html | 28 +++ 8 files changed, 942 insertions(+), 9 deletions(-) create mode 100644 main_copy.py create mode 100644 templates/forecast.html create mode 100644 templates/history_range.html create mode 100644 templates/hourly_forecast.html create mode 100644 templates/ping.html create mode 100644 templates/test.html diff --git a/main.py b/main.py index 14b869c..b58bfcd 100644 --- a/main.py +++ b/main.py @@ -6,6 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from db import get_session, engine, Base from models import WeatherRecord from datetime import datetime +from fastapi.responses import HTMLResponse, JSONResponse app = FastAPI() templates = Jinja2Templates(directory="templates") @@ -14,8 +15,74 @@ CITIES = { "warszawa": (52.23, 21.01), "krakow": (50.06, 19.94), "gdansk": (54.35, 18.65), + "wroclaw": (51.11, 17.03), + "poznan": (52.41, 16.93), + "szczecin": (53.43, 14.55), + "bydgoszcz": (53.12, 18.01), + "lublin": (51.25, 22.57), + "bialystok": (53.13, 23.15), + "katowice": (50.26, 19.02), + "lodz": (51.77, 19.46), + "torun": (53.01, 18.60), + "kielce": (50.87, 20.63), + "rzeszow": (50.04, 22.00), + "opole": (50.67, 17.93), + "zielona_gora": (51.94, 15.50), + "gorzow_wlkp": (52.73, 15.24), + "olsztyn": (53.78, 20.48), + "radom": (51.40, 21.15), + "plock": (52.55, 19.70), + "elblag": (54.16, 19.40), + "tarnow": (50.01, 20.99), + "chorzow": (50.30, 18.95), + "gliwice": (50.30, 18.67), + "zabrze": (50.30, 18.78), + "rybnik": (50.10, 18.55), + "walbrzych": (50.77, 16.28), + "legnica": (51.21, 16.16), + "pila": (53.15, 16.74), + "suwalki": (54.10, 22.93), + "siedlce": (52.17, 22.29), + "piotrkow_tryb": (51.40, 19.70), + "nowy_sacz": (49.62, 20.69), + "przemysl": (49.78, 22.77), + "zamosc": (50.72, 23.25), + "chelm": (51.14, 23.47), + "koszalin": (54.19, 16.18), + "slupsk": (54.46, 17.03), + "grudziadz": (53.48, 18.75), + "jaworzno": (50.20, 19.27), + "tarnobrzeg": (50.58, 21.68), + "ostrow_wlkp": (51.65, 17.81), + "konin": (52.22, 18.26), + "leszno": (51.84, 16.57), + "stargard": (53.34, 15.05), + "lubin": (51.40, 16.20), + "mielec": (50.28, 21.42), + "pabianice": (51.66, 19.35), + "glogow": (51.66, 16.08), + "ostroleka": (53.09, 21.56), + "siemianowice_sl": (50.31, 19.03), + "swidnica": (50.84, 16.49), + "skierniewice": (51.97, 20.15), + "bedzin": (50.33, 19.13), + "pulawy": (51.42, 21.97), + "starachowice": (51.05, 21.08), + "nowy_targ": (49.48, 20.03), + "radomsko": (51.07, 19.45), + "wloclawek": (52.65, 19.07), + "lubartow": (51.46, 22.61), + "lomza": (53.18, 22.07), + "klodzko": (50.43, 16.65), + "biala_podlaska": (52.03, 23.13), + "pruszkow": (52.17, 20.80), + "jaslo": (49.75, 21.47), + "dzierzoniow": (50.73, 16.65), + "bielsk_podlaski": (52.77, 23.19), } + + @app.on_event("startup") async def startup(): async with engine.begin() as conn: @@ -34,6 +101,7 @@ async def get_weather(city: str = Query("warszawa"), session: AsyncSession = Dep data = res.json() current = data.get("current_weather", {}) + record = WeatherRecord( city=city.capitalize(), temperature=current.get("temperature"), @@ -50,6 +118,7 @@ async def get_weather(city: str = Query("warszawa"), session: AsyncSession = Dep "time": record.time } + @app.get("/history") async def get_history(city: str = Query("warszawa"), session: AsyncSession = Depends(get_session)): stmt = select(WeatherRecord).where(WeatherRecord.city.ilike(city)).order_by(WeatherRecord.time.desc()).limit(10) @@ -78,9 +147,10 @@ async def view_history(request: Request, city: str = "warszawa", session: AsyncS @app.get("/ping") -async def ping(): - return {"status": "ok"} - +async def ping(request: Request): + if "text/html" in request.headers.get("accept", ""): + return templates.TemplateResponse("ping.html", {"request": request}) + return JSONResponse({"status": "ok"}) @app.get("/weather/geo") async def get_weather_by_coords( @@ -121,3 +191,297 @@ async def get_weather_by_coords( "windspeed": record.windspeed, "time": record.time } +@app.get("/forecast", response_class=HTMLResponse) +async def get_forecast( + request: Request, + city: str = Query("warszawa"), + days: int = Query(3, ge=1, le=16) +): + coords = CITIES.get(city.lower()) + if not coords: + return templates.TemplateResponse( + "forecast.html", + { + "request": request, + "city": city.capitalize(), + "forecast": None + } + ) + + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={coords[0]}&longitude={coords[1]}" + f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum" + f"&timezone=Europe/Warsaw" + f"&forecast_days={days}" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + daily = data.get("daily", {}) + + accept = request.headers.get("accept", "") + if "text/html" in accept: + return templates.TemplateResponse( + "forecast.html", + { + "request": request, + "city": city.capitalize(), + "forecast": daily, + "error": None, + } + ) + else: + return JSONResponse(content={ + "city": city.capitalize(), + "forecast": daily, + }) + + +@app.get("/forecast/geo", response_class=HTMLResponse) +async def get_forecast_geo( + request: Request, + latitude: float = Query(..., ge=-90, le=90), + longitude: float = Query(..., ge=-180, le=180), + days: int = Query(3, ge=1, le=16) +): + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={latitude}&longitude={longitude}" + f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum" + f"&timezone=Europe/Warsaw" + f"&forecast_days={days}" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + daily = data.get("daily", {}) + + accept = request.headers.get("accept", "") + if "text/html" in accept: + return templates.TemplateResponse( + "forecast.html", + { + "request": request, + "city": f"Lat: {latitude}, Lon: {longitude}", + "forecast": daily, + "error": None, + } + ) + else: + return JSONResponse(content={ + "latitude": latitude, + "longitude": longitude, + "forecast": daily + }) + + +@app.get("/forecast/hourly/geo", response_class=HTMLResponse) +async def get_hourly_forecast_geo( + request: Request, + latitude: float = Query(..., ge=-90, le=90), + longitude: float = Query(..., ge=-180, le=180), + hours: int = Query(12, ge=1, le=48) +): + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={latitude}&longitude={longitude}" + f"&hourly=temperature_2m,windspeed_10m,precipitation" + f"&timezone=Europe/Warsaw" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + hourly_data = {} + for key, values in data.get("hourly", {}).items(): + hourly_data[key] = values[:hours] + + accept = request.headers.get("accept", "") + if "text/html" in accept: + return templates.TemplateResponse( + "hourly_forecast.html", + { + "request": request, + "city": f"Lat: {latitude}, Lon: {longitude}", + "hourly_forecast": hourly_data, + "error": None, + } + ) + else: + return JSONResponse(content={ + "latitude": latitude, + "longitude": longitude, + "hourly_forecast": hourly_data + }) + +@app.get("/forecast/hourly") +async def get_hourly_forecast_city( + request: Request, + city: str = Query(...), + hours: int = Query(12, ge=1, le=48) +): + coords = CITIES.get(city.lower()) + if not coords: + error_data = {"error": "Miasto nieobsługiwane"} + accept = request.headers.get("accept", "") + if "text/html" in accept: + return templates.TemplateResponse( + "hourly_forecast.html", + { + "request": request, + "city": city.capitalize(), + "hourly_forecast": None, + "error": error_data["error"], + } + ) + else: + raise HTTPException(status_code=404, detail=error_data["error"]) + latitude, longitude = coords + + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={latitude}&longitude={longitude}" + f"&hourly=temperature_2m,windspeed_10m,precipitation" + f"&timezone=Europe/Warsaw" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + hourly_data = {} + for key, values in data.get("hourly", {}).items(): + hourly_data[key] = values[:hours] + + accept = request.headers.get("accept", "") + if "text/html" in accept: + return templates.TemplateResponse( + "hourly_forecast.html", + { + "request": request, + "city": city.capitalize(), + "hourly_forecast": hourly_data, + "error": None, + } + ) + else: + return JSONResponse(content={ + "city": city.capitalize(), + "hourly_forecast": hourly_data + }) + +@app.get("/history-range") +async def get_weather_history_range( + request: Request, + city: str = Query(..., description="Nazwa miasta, np. warszawa"), + start_date: str = Query(..., description="Początkowa data w formacie YYYY-MM-DD"), + end_date: str = Query(..., description="Końcowa data w formacie YYYY-MM-DD") +): + coords = CITIES.get(city.lower()) + if not coords: + error_data = {"error": "Miasto nieobsługiwane"} + accept = request.headers.get("accept", "") + if "text/html" in accept: + return templates.TemplateResponse( + "history_range.html", + { + "request": request, + "city": city.capitalize(), + "start_date": start_date, + "end_date": end_date, + "history": None, + "error": error_data["error"] + } + ) + else: + raise HTTPException(status_code=404, detail=error_data["error"]) + + latitude, longitude = coords + + url = ( + f"https://archive-api.open-meteo.com/v1/archive?" + f"latitude={latitude}&longitude={longitude}" + f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum" + f"&start_date={start_date}&end_date={end_date}" + f"&timezone=Europe/Warsaw" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + daily = data.get("daily", {}) + + accept = request.headers.get("accept", "") + if "text/html" in accept: + return templates.TemplateResponse( + "history_range.html", + { + "request": request, + "city": city.capitalize(), + "start_date": start_date, + "end_date": end_date, + "history": daily, + "error": None + } + ) + else: + return JSONResponse(content={ + "city": city.capitalize(), + "start_date": start_date, + "end_date": end_date, + "history": daily + }) + +@app.get("/history-range/geo") +async def get_weather_history_range_geo( + request: Request, + latitude: float = Query(..., ge=-90, le=90, description="Szerokość geograficzna"), + longitude: float = Query(..., ge=-180, le=180, description="Długość geograficzna"), + start_date: str = Query(..., description="Początkowa data w formacie YYYY-MM-DD"), + end_date: str = Query(..., description="Końcowa data w formacie YYYY-MM-DD") +): + url = ( + f"https://archive-api.open-meteo.com/v1/archive?" + f"latitude={latitude}&longitude={longitude}" + f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum" + f"&start_date={start_date}&end_date={end_date}" + f"&timezone=Europe/Warsaw" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + daily = data.get("daily", {}) + + accept = request.headers.get("accept", "") + if "text/html" in accept: + city_name = f"({latitude}, {longitude})" + + return templates.TemplateResponse( + "history_range.html", + { + "request": request, + "city": city_name, + "start_date": start_date, + "end_date": end_date, + "history": daily, + "error": None + } + ) + else: + return JSONResponse(content={ + "latitude": latitude, + "longitude": longitude, + "start_date": start_date, + "end_date": end_date, + "history": daily + }) + diff --git a/main_copy.py b/main_copy.py new file mode 100644 index 0000000..4c19aa7 --- /dev/null +++ b/main_copy.py @@ -0,0 +1,298 @@ +from fastapi import FastAPI, Depends, Query, Request +from fastapi.templating import Jinja2Templates +import httpx +from sqlalchemy.future import select +from sqlalchemy.ext.asyncio import AsyncSession +from db import get_session, engine, Base +from models import WeatherRecord +from datetime import datetime + +app = FastAPI() +templates = Jinja2Templates(directory="templates") + +CITIES = { + "warszawa": (52.23, 21.01), + "krakow": (50.06, 19.94), + "gdansk": (54.35, 18.65), +} + +@app.on_event("startup") +async def startup(): + async with engine.begin() as conn: + await conn.run_sync(Base.metadata.create_all) + +@app.get("/weather") +async def get_weather(city: str = Query("warszawa"), session: AsyncSession = Depends(get_session)): + coords = CITIES.get(city.lower()) + if not coords: + return {"error": "Miasto nieobsługiwane"} + + url = f"https://api.open-meteo.com/v1/forecast?latitude={coords[0]}&longitude={coords[1]}¤t_weather=true" + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + current = data.get("current_weather", {}) + + record = WeatherRecord( + city=city.capitalize(), + temperature=current.get("temperature"), + windspeed=current.get("windspeed"), + time=datetime.fromisoformat(current.get("time")), + ) + session.add(record) + await session.commit() + + return { + "city": record.city, + "temperature": record.temperature, + "windspeed": record.windspeed, + "time": record.time + } + +@app.get("/history") +async def get_history(city: str = Query("warszawa"), session: AsyncSession = Depends(get_session)): + stmt = select(WeatherRecord).where(WeatherRecord.city.ilike(city)).order_by(WeatherRecord.time.desc()).limit(10) + result = await session.execute(stmt) + records = result.scalars().all() + return [ + { + "city": r.city, + "temperature": r.temperature, + "windspeed": r.windspeed, + "time": r.time.isoformat() + } + for r in records + ] + +@app.get("/view") +async def view_history(request: Request, city: str = "warszawa", session: AsyncSession = Depends(get_session)): + stmt = select(WeatherRecord).where(WeatherRecord.city.ilike(city)).order_by(WeatherRecord.time.desc()).limit(10) + result = await session.execute(stmt) + records = result.scalars().all() + return templates.TemplateResponse("history.html", { + "request": request, + "city": city.capitalize(), + "records": records + }) + + +@app.get("/ping") +async def ping(): + return {"status": "ok"} + + +@app.get("/weather/geo") +async def get_weather_by_coords( + latitude: float = Query(..., ge=-90, le=90), + longitude: float = Query(..., ge=-180, le=180), + session: AsyncSession = Depends(get_session) +): + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={latitude}&longitude={longitude}¤t_weather=true" + ) + + async with httpx.AsyncClient() as client: + try: + res = await client.get(url, timeout=10.0) + res.raise_for_status() + data = res.json() + except httpx.RequestError as e: + raise HTTPException(status_code=502, detail=f"Błąd połączenia: {e}") + except httpx.HTTPStatusError as e: + raise HTTPException(status_code=502, detail=f"Błąd API pogodowego: {e}") + + current = data.get("current_weather", {}) + record = WeatherRecord( + city="Custom Location", + temperature=current.get("temperature"), + windspeed=current.get("windspeed"), + time=datetime.fromisoformat(current.get("time")), + ) + session.add(record) + await session.commit() + + return { + "city": record.city, + "latitude": latitude, + "longitude": longitude, + "temperature": record.temperature, + "windspeed": record.windspeed, + "time": record.time + } + +@app.get("/forecast") +async def get_forecast( + city: str = Query("warszawa"), + days: int = Query(3, ge=1, le=16) +): + coords = CITIES.get(city.lower()) + if not coords: + return {"error": "Miasto nieobsługiwane"} + + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={coords[0]}&longitude={coords[1]}" + f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum" + f"&timezone=Europe/Warsaw" + f"&forecast_days={days}" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + daily = data.get("daily", {}) + + return { + "city": city.capitalize(), + "forecast": daily + } + + +@app.get("/forecast/geo") +async def get_forecast_geo( + latitude: float = Query(..., ge=-90, le=90), + longitude: float = Query(..., ge=-180, le=180), + days: int = Query(3, ge=1, le=16) +): + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={latitude}&longitude={longitude}" + f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum" + f"&timezone=Europe/Warsaw" + f"&forecast_days={days}" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + daily = data.get("daily", {}) + + return { + "latitude": latitude, + "longitude": longitude, + "forecast": daily + } + +@app.get("/forecast/hourly/geo") +async def get_hourly_forecast_geo( + latitude: float = Query(..., ge=-90, le=90), + longitude: float = Query(..., ge=-180, le=180), + hours: int = Query(12, ge=1, le=48) +): + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={latitude}&longitude={longitude}" + f"&hourly=temperature_2m,windspeed_10m,precipitation" + f"&timezone=Europe/Warsaw" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + hourly_data = {} + for key, values in data.get("hourly", {}).items(): + hourly_data[key] = values[:hours] + + return { + "latitude": latitude, + "longitude": longitude, + "hourly_forecast": hourly_data + } + +@app.get("/forecast/hourly") +async def get_hourly_forecast_city( + city: str = Query(...), + hours: int = Query(12, ge=1, le=48) +): + coords = CITIES.get(city.lower()) + if not coords: + raise HTTPException(status_code=404, detail="Miasto nieobsługiwane") + + latitude, longitude = coords + + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={latitude}&longitude={longitude}" + f"&hourly=temperature_2m,windspeed_10m,precipitation" + f"&timezone=Europe/Warsaw" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + hourly_data = {} + for key, values in data.get("hourly", {}).items(): + hourly_data[key] = values[:hours] + + return { + "city": city.capitalize(), + "hourly_forecast": hourly_data + } + +@app.get("/history-range") +async def get_weather_history_range( + city: str = Query(..., description="Nazwa miasta, np. warszawa"), + start_date: str = Query(..., description="Początkowa data w formacie YYYY-MM-DD"), + end_date: str = Query(..., description="Końcowa data w formacie YYYY-MM-DD") +): + coords = CITIES.get(city.lower()) + if not coords: + raise HTTPException(status_code=404, detail="Miasto nieobsługiwane") + latitude, longitude = coords + + url = ( + f"https://archive-api.open-meteo.com/v1/archive?" + f"latitude={latitude}&longitude={longitude}" + f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum" + f"&start_date={start_date}&end_date={end_date}" + f"&timezone=Europe/Warsaw" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + daily = data.get("daily", {}) + + return { + "city": city.capitalize(), + "start_date": start_date, + "end_date": end_date, + "history": daily + } + +@app.get("/history-range/geo") +async def get_weather_history_range_geo( + latitude: float = Query(..., ge=-90, le=90, description="Szerokość geograficzna"), + longitude: float = Query(..., ge=-180, le=180, description="Długość geograficzna"), + start_date: str = Query(..., description="Początkowa data w formacie YYYY-MM-DD"), + end_date: str = Query(..., description="Końcowa data w formacie YYYY-MM-DD") +): + url = ( + f"https://archive-api.open-meteo.com/v1/archive?" + f"latitude={latitude}&longitude={longitude}" + f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum" + f"&start_date={start_date}&end_date={end_date}" + f"&timezone=Europe/Warsaw" + ) + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + daily = data.get("daily", {}) + + return { + "latitude": latitude, + "longitude": longitude, + "start_date": start_date, + "end_date": end_date, + "history": daily + } diff --git a/templates/forecast.html b/templates/forecast.html new file mode 100644 index 0000000..37630d0 --- /dev/null +++ b/templates/forecast.html @@ -0,0 +1,69 @@ + + + + + Prognoza pogody - {{ city }} + + + +

Prognoza pogody dla {{ city }}

+ + {% if error %} +

{{ error }}

+ {% elif forecast and forecast.time %} + + + + + + + + + + + {% for i in range(forecast.time|length) %} + + + + + + + {% endfor %} + +
DataTemperatura maks. (°C)Temperatura min. (°C)Opady (mm)
{{ forecast.time[i] }}{{ forecast.temperature_2m_max[i] }}{{ forecast.temperature_2m_min[i] }}{{ forecast.precipitation_sum[i] }}
+ {% else %} +

Brak danych pogodowych.

+ {% endif %} + + diff --git a/templates/history.html b/templates/history.html index 99643a7..2a1710a 100644 --- a/templates/history.html +++ b/templates/history.html @@ -1,15 +1,44 @@ - + - Historia pogody - {{ city }} + + Historia zapytan o {{ city }} -

Historia pogody – {{ city }}

+

Historia zapytan o {{ city }}

+ diff --git a/templates/history_range.html b/templates/history_range.html new file mode 100644 index 0000000..3754067 --- /dev/null +++ b/templates/history_range.html @@ -0,0 +1,67 @@ + + + + + Historia pogody - {{ city }} + + + +

Historia pogody dla {{ city }}
od {{ start_date }} do {{ end_date }}

+ + {% if error %} +

{{ error }}

+ {% elif history %} +
Data
+ + + + + + + + + + {% for i in range(history["time"]|length) %} + + + + + + + {% endfor %} + +
DataTemp. maks. (°C)Temp. min. (°C)Opady (mm)
{{ history["time"][i] }}{{ history["temperature_2m_max"][i] }}{{ history["temperature_2m_min"][i] }}{{ history["precipitation_sum"][i] }}
+ {% endif %} + + diff --git a/templates/hourly_forecast.html b/templates/hourly_forecast.html new file mode 100644 index 0000000..69029c6 --- /dev/null +++ b/templates/hourly_forecast.html @@ -0,0 +1,67 @@ + + + + + Prognoza godzinowa - {{ city }} + + + +

Prognoza godzinowa dla {{ city }}

+ + {% if error %} +

{{ error }}

+ {% elif hourly_forecast %} + + + + + + + + + + + {% for i in range(hourly_forecast["time"]|length) %} + + + + + + + {% endfor %} + +
GodzinaTemp. (°C)Wiatr (km/h)Opady (mm)
{{ hourly_forecast["time"][i] }}{{ hourly_forecast["temperature_2m"][i] }}{{ hourly_forecast["windspeed_10m"][i] }}{{ hourly_forecast["precipitation"][i] }}
+ {% endif %} + + diff --git a/templates/ping.html b/templates/ping.html new file mode 100644 index 0000000..d5de17b --- /dev/null +++ b/templates/ping.html @@ -0,0 +1,11 @@ + + + + + Ping status + + +

Status: OK

+

Serwer działa poprawnie.

+ + diff --git a/templates/test.html b/templates/test.html new file mode 100644 index 0000000..99643a7 --- /dev/null +++ b/templates/test.html @@ -0,0 +1,28 @@ + + + + Historia pogody - {{ city }} + + + +

Historia pogody – {{ city }}

+ + + + + + + {% for r in records %} + + + + + + {% endfor %} +
DataTemperatura (°C)Wiatr (m/s)
{{ r.time.strftime('%Y-%m-%d %H:%M') }}{{ r.temperature }}{{ r.windspeed }}
+ +