Add FastAPI backend with PostGIS-backed nearby search
FastAPI service backed by PostgreSQL+PostGIS: cities/places/place_content schema (normalized per-language, per-length content for easy future re-ingestion), Alembic migration, an iterative-radius-expansion nearby search endpoint, a name-search fallback for denied-location flows, and a YAML seed loader CLI. Verified end-to-end against a live Docker Postgres+PostGIS instance (migration, city seed, place/content CRUD, and nearby radius expansion all confirmed working via curl). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
2acc5dfa2e
commit
d2ab424e7e
43 changed files with 1058 additions and 0 deletions
34
backend/app/api/routes/cities.py
Normal file
34
backend/app/api/routes/cities.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
from geoalchemy2 import Geometry
|
||||
from sqlalchemy import cast, func, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.db.session import get_db
|
||||
from app.models.city import City
|
||||
from app.schemas.city import CityOut
|
||||
from app.schemas.common import LatLon, LocalizedName
|
||||
|
||||
router = APIRouter(tags=["cities"])
|
||||
|
||||
|
||||
@router.get("/cities", response_model=list[CityOut])
|
||||
def list_cities(db: Session = Depends(get_db)) -> list[CityOut]:
|
||||
stmt = select(
|
||||
City,
|
||||
func.ST_X(cast(City.center_point, Geometry)).label("lon"),
|
||||
func.ST_Y(cast(City.center_point, Geometry)).label("lat"),
|
||||
)
|
||||
rows = db.execute(stmt).all()
|
||||
|
||||
out = []
|
||||
for city, lon, lat in rows:
|
||||
center = LatLon(lat=lat, lon=lon) if lat is not None and lon is not None else None
|
||||
out.append(
|
||||
CityOut(
|
||||
id=city.id,
|
||||
slug=city.slug,
|
||||
name=LocalizedName(ru=city.name_ru, en=city.name_en),
|
||||
center=center,
|
||||
)
|
||||
)
|
||||
return out
|
||||
Loading…
Add table
Add a link
Reference in a new issue