Fix circular reference recursion in JSON serialization
Dataclass models have parent back-references (TrackLayout→Circuit→ Locality→Country) causing infinite recursion in dataclasses.asdict(). Add to_dict() methods that exclude parent refs, use them in API endpoints.
This commit is contained in:
+5
-5
@@ -67,7 +67,7 @@ async def root():
|
|||||||
async def get_countries():
|
async def get_countries():
|
||||||
"""Get list of all available countries with their slugs"""
|
"""Get list of all available countries with their slugs"""
|
||||||
return {
|
return {
|
||||||
"countries": circuit_service.get_countries_list()
|
"countries": [c.to_dict() for c in circuit_service.get_countries_list()]
|
||||||
}
|
}
|
||||||
|
|
||||||
@app.get("/circuits/{country_slug}")
|
@app.get("/circuits/{country_slug}")
|
||||||
@@ -76,7 +76,7 @@ async def get_cities(country_slug: str):
|
|||||||
cities = circuit_service.get_localities_list(country_slug)
|
cities = circuit_service.get_localities_list(country_slug)
|
||||||
if not cities:
|
if not cities:
|
||||||
raise HTTPException(status_code=404, detail="Country not found")
|
raise HTTPException(status_code=404, detail="Country not found")
|
||||||
return {"cities": cities}
|
return {"cities": [c.to_dict() for c in cities]}
|
||||||
|
|
||||||
@app.get("/circuits/{country_slug}/{city_slug}")
|
@app.get("/circuits/{country_slug}/{city_slug}")
|
||||||
async def get_circuits(country_slug: str, city_slug: str):
|
async def get_circuits(country_slug: str, city_slug: str):
|
||||||
@@ -84,7 +84,7 @@ async def get_circuits(country_slug: str, city_slug: str):
|
|||||||
circuits = circuit_service.get_circuits_list(country_slug, city_slug)
|
circuits = circuit_service.get_circuits_list(country_slug, city_slug)
|
||||||
if not circuits:
|
if not circuits:
|
||||||
raise HTTPException(status_code=404, detail="City not found")
|
raise HTTPException(status_code=404, detail="City not found")
|
||||||
return {"circuits": circuits}
|
return {"circuits": [c.to_dict() for c in circuits]}
|
||||||
|
|
||||||
@app.get("/circuits/{country_slug}/{city_slug}/{circuit_slug}")
|
@app.get("/circuits/{country_slug}/{city_slug}/{circuit_slug}")
|
||||||
async def get_circuit_details(country_slug: str, city_slug: str, circuit_slug: str):
|
async def get_circuit_details(country_slug: str, city_slug: str, circuit_slug: str):
|
||||||
@@ -92,7 +92,7 @@ async def get_circuit_details(country_slug: str, city_slug: str, circuit_slug: s
|
|||||||
circuit_details = circuit_service.get_circuit_details(country_slug, city_slug, circuit_slug)
|
circuit_details = circuit_service.get_circuit_details(country_slug, city_slug, circuit_slug)
|
||||||
if not circuit_details:
|
if not circuit_details:
|
||||||
raise HTTPException(status_code=404, detail="Circuit not found")
|
raise HTTPException(status_code=404, detail="Circuit not found")
|
||||||
return circuit_details
|
return circuit_details.to_dict()
|
||||||
|
|
||||||
@app.get("/circuits/{country_slug}/{city_slug}/{circuit_slug}/layout/{layout_slug}")
|
@app.get("/circuits/{country_slug}/{city_slug}/{circuit_slug}/layout/{layout_slug}")
|
||||||
async def get_layout_details(country_slug: str, city_slug: str, circuit_slug: str, layout_slug: str):
|
async def get_layout_details(country_slug: str, city_slug: str, circuit_slug: str, layout_slug: str):
|
||||||
@@ -100,7 +100,7 @@ async def get_layout_details(country_slug: str, city_slug: str, circuit_slug: st
|
|||||||
layout_details = circuit_service.get_layout_details(country_slug, city_slug, circuit_slug, layout_slug)
|
layout_details = circuit_service.get_layout_details(country_slug, city_slug, circuit_slug, layout_slug)
|
||||||
if not layout_details:
|
if not layout_details:
|
||||||
raise HTTPException(status_code=404, detail="Layout not found")
|
raise HTTPException(status_code=404, detail="Layout not found")
|
||||||
return layout_details
|
return layout_details.to_dict()
|
||||||
|
|
||||||
@app.get("/tracks/{country_slug}/{city_slug}/{circuit_slug}/year/{year}/{image_format}")
|
@app.get("/tracks/{country_slug}/{city_slug}/{circuit_slug}/year/{year}/{image_format}")
|
||||||
async def get_track_by_year(
|
async def get_track_by_year(
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ class Circuit:
|
|||||||
locality: 'Locality'
|
locality: 'Locality'
|
||||||
layouts: dict[str, TrackLayout]
|
layouts: dict[str, TrackLayout]
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"slug": self.slug,
|
||||||
|
"name": self.name,
|
||||||
|
"urls": {"wikipedia": self.urls.wikipedia, "fandom": self.urls.fandom},
|
||||||
|
"layouts": {k: v.to_dict() for k, v in self.layouts.items()},
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, locality: 'Locality', slug: str, data: dict) -> 'Circuit':
|
def from_dict(cls, locality: 'Locality', slug: str, data: dict) -> 'Circuit':
|
||||||
circuit = cls(
|
circuit = cls(
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ class Country:
|
|||||||
name: str
|
name: str
|
||||||
localities: dict[str, Locality]
|
localities: dict[str, Locality]
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"slug": self.slug,
|
||||||
|
"name": self.name,
|
||||||
|
"localities": {k: v.to_dict() for k, v in self.localities.items()},
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, slug: str, data: dict):
|
def from_dict(cls, slug: str, data: dict):
|
||||||
country = cls(
|
country = cls(
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ class Locality:
|
|||||||
country: 'Country'
|
country: 'Country'
|
||||||
circuits: dict[str, Circuit]
|
circuits: dict[str, Circuit]
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"slug": self.slug,
|
||||||
|
"name": self.name,
|
||||||
|
"circuits": {k: v.to_dict() for k, v in self.circuits.items()},
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, country: 'Country', slug: str, data: dict):
|
def from_dict(cls, country: 'Country', slug: str, data: dict):
|
||||||
locality = cls(
|
locality = cls(
|
||||||
|
|||||||
@@ -27,6 +27,13 @@ class TrackLayout:
|
|||||||
circuit=circuit
|
circuit=circuit
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"slug": self.slug,
|
||||||
|
"description": self.description,
|
||||||
|
"imageUrl": self.imageUrl,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def coordinates(self) -> list[tuple[float, float]]:
|
def coordinates(self) -> list[tuple[float, float]]:
|
||||||
return self._geo_data.features[0].geometry.coordinates
|
return self._geo_data.features[0].geometry.coordinates
|
||||||
|
|||||||
Reference in New Issue
Block a user