122 lines
3.9 KiB
Python
122 lines
3.9 KiB
Python
|
|
"""CLI to load seed YAML content into the database, upserting by slug.
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
python -m seed.seed_loader --cities seed/cities.yaml
|
||
|
|
python -m seed.seed_loader --file seed/moscow_red_square.yaml
|
||
|
|
"""
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import yaml
|
||
|
|
|
||
|
|
from app.db.session import SessionLocal
|
||
|
|
from app.models.city import City
|
||
|
|
from app.models.place import Place
|
||
|
|
from app.models.place_content import PlaceContent
|
||
|
|
|
||
|
|
|
||
|
|
def load_cities(path: Path) -> None:
|
||
|
|
data = yaml.safe_load(path.read_text(encoding="utf-8"))
|
||
|
|
db = SessionLocal()
|
||
|
|
try:
|
||
|
|
for c in data["cities"]:
|
||
|
|
city = db.query(City).filter(City.slug == c["slug"]).one_or_none()
|
||
|
|
if city is None:
|
||
|
|
city = City(slug=c["slug"], name_ru=c["name_ru"], name_en=c["name_en"])
|
||
|
|
db.add(city)
|
||
|
|
else:
|
||
|
|
city.name_ru = c["name_ru"]
|
||
|
|
city.name_en = c["name_en"]
|
||
|
|
center = c.get("center")
|
||
|
|
if center is not None:
|
||
|
|
city.center_point = f"SRID=4326;POINT({center['lon']} {center['lat']})"
|
||
|
|
db.flush()
|
||
|
|
db.commit()
|
||
|
|
print(f"Loaded {len(data['cities'])} cities from {path.name}")
|
||
|
|
finally:
|
||
|
|
db.close()
|
||
|
|
|
||
|
|
|
||
|
|
def _upsert_place(db, city_id: int, place_data: dict) -> Place:
|
||
|
|
place = db.query(Place).filter(Place.slug == place_data["slug"]).one_or_none()
|
||
|
|
if place is None:
|
||
|
|
place = Place(city_id=city_id, slug=place_data["slug"], category=place_data["category"])
|
||
|
|
db.add(place)
|
||
|
|
else:
|
||
|
|
place.category = place_data["category"]
|
||
|
|
|
||
|
|
place.city_id = city_id
|
||
|
|
place.address = place_data.get("address")
|
||
|
|
place.district = place_data.get("district")
|
||
|
|
place.built_year = place_data.get("built_year")
|
||
|
|
place.architect_builder = place_data.get("architect_builder")
|
||
|
|
place.architectural_style = place_data.get("architectural_style")
|
||
|
|
place.notable_people = place_data.get("notable_people")
|
||
|
|
|
||
|
|
loc = place_data["location"]
|
||
|
|
place.location = f"SRID=4326;POINT({loc['lon']} {loc['lat']})"
|
||
|
|
|
||
|
|
db.flush()
|
||
|
|
return place
|
||
|
|
|
||
|
|
|
||
|
|
def _upsert_content(db, place_id: int, language: str, length: str, title: str, body: str) -> None:
|
||
|
|
content = (
|
||
|
|
db.query(PlaceContent)
|
||
|
|
.filter(
|
||
|
|
PlaceContent.place_id == place_id,
|
||
|
|
PlaceContent.language == language,
|
||
|
|
PlaceContent.length == length,
|
||
|
|
)
|
||
|
|
.one_or_none()
|
||
|
|
)
|
||
|
|
if content is None:
|
||
|
|
db.add(PlaceContent(place_id=place_id, language=language, length=length, title=title, body=body))
|
||
|
|
else:
|
||
|
|
content.title = title
|
||
|
|
content.body = body
|
||
|
|
|
||
|
|
|
||
|
|
def load_places(path: Path) -> None:
|
||
|
|
data = yaml.safe_load(path.read_text(encoding="utf-8"))
|
||
|
|
city_slug = data["city"]
|
||
|
|
|
||
|
|
db = SessionLocal()
|
||
|
|
try:
|
||
|
|
city = db.query(City).filter(City.slug == city_slug).one_or_none()
|
||
|
|
if city is None:
|
||
|
|
raise SystemExit(
|
||
|
|
f"City '{city_slug}' not found. Run `--cities seed/cities.yaml` first."
|
||
|
|
)
|
||
|
|
|
||
|
|
for place_data in data["places"]:
|
||
|
|
place = _upsert_place(db, city.id, place_data)
|
||
|
|
titles = place_data.get("title", {})
|
||
|
|
for language, lengths in place_data["content"].items():
|
||
|
|
title = titles.get(language, place_data["slug"])
|
||
|
|
for length, body in lengths.items():
|
||
|
|
_upsert_content(db, place.id, language, length, title, body.strip())
|
||
|
|
|
||
|
|
db.commit()
|
||
|
|
print(f"Loaded {len(data['places'])} places from {path.name}")
|
||
|
|
finally:
|
||
|
|
db.close()
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
||
|
|
group = parser.add_mutually_exclusive_group(required=True)
|
||
|
|
group.add_argument("--cities", help="Path to a cities YAML file")
|
||
|
|
group.add_argument("--file", help="Path to a places YAML file")
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
if args.cities:
|
||
|
|
load_cities(Path(args.cities))
|
||
|
|
else:
|
||
|
|
load_places(Path(args.file))
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|