-
Notifications
You must be signed in to change notification settings - Fork 1
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 #3 from pingpingy1/main
[Feat] 기본 데이터 제공 API 작성
- Loading branch information
Showing
11 changed files
with
296 additions
and
61 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -120,7 +120,7 @@ celerybeat.pid | |
*.sage.py | ||
|
||
# Environments | ||
.env | ||
# .env | ||
.venv | ||
env/ | ||
venv/ | ||
|
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,3 +1,2 @@ | ||
# required environment variables | ||
MONGO_CONNECTION_URI=mongodb://localhost:27017 | ||
MONGO_DB_NAME=council | ||
MONGO_CONNECTION_URI=mongodb://localhost:27017 |
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,4 +1,4 @@ | ||
FROM python:3.10 | ||
FROM python:3.11 | ||
|
||
WORKDIR /src | ||
|
||
|
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,21 +1,24 @@ | ||
from fastapi import FastAPI, Request | ||
from dotenv import load_dotenv | ||
from routers import scrapResult | ||
from routers import scrapResult, commonInfo | ||
from contextlib import asynccontextmanager | ||
from typing import Dict | ||
from model import MongoDB | ||
from model.ResponseType import ChartResponse, SexInfo, PartyInfo, AgeInfo | ||
|
||
|
||
|
||
@asynccontextmanager | ||
async def initMongo(app: FastAPI): | ||
MongoDB.MongoDB().connect() | ||
MongoDB.client.connect() | ||
yield | ||
MongoDB.MongoDB().close() | ||
MongoDB.client.close() | ||
|
||
|
||
new = ChartResponse[SexInfo] | ||
|
||
app = FastAPI(lifespan=initMongo, responses={404: {"description": "Not found"}}) | ||
|
||
|
||
app.include_router(scrapResult.router) | ||
app.include_router(commonInfo.router) |
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,16 @@ | ||
from pydantic import BaseModel | ||
|
||
|
||
SUCCESS = 200 | ||
REGION_CODE_ERR = 400 | ||
|
||
|
||
class MessageResponse(BaseModel): | ||
message: str | ||
code: int = SUCCESS | ||
|
||
|
||
class ErrorResponse(BaseModel): | ||
error: str | ||
code: int | ||
message: str |
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,17 @@ | ||
from pydantic import BaseModel | ||
|
||
|
||
class LocalInfo(BaseModel): | ||
name: str | ||
id: int | ||
|
||
|
||
class RegionInfo(BaseModel): | ||
name: str | ||
id: int | ||
local: list[LocalInfo] | ||
|
||
|
||
class PartyInfo(BaseModel): | ||
name: str | ||
color: str |
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,18 +1,79 @@ | ||
from pydantic import BaseModel, Field | ||
from pydantic import BaseModel | ||
from enum import StrEnum | ||
from typing import TypeVar, Generic | ||
|
||
|
||
class SexType(StrEnum): | ||
male = "남" | ||
female = "여" | ||
|
||
|
||
class FactorType(StrEnum): | ||
sex = "sex" | ||
age = "age" | ||
party = "party" | ||
|
||
|
||
# ============================================== | ||
# = Template Data Types = | ||
# ============================================== | ||
class SexTemplateData(BaseModel): | ||
sexDiversityIndex: float | ||
|
||
|
||
class AgeTemplateData(BaseModel): | ||
ageDiversityIndex: float | ||
|
||
|
||
class PartyTemplateData(BaseModel): | ||
partyDiversityIndex: float | ||
|
||
|
||
# ============================================== | ||
# = Chart Data Types = | ||
# ============================================== | ||
class SexChartDataPoint(BaseModel): | ||
sex: SexType | ||
count: int | ||
|
||
|
||
|
||
|
||
class AgeChartDataPoint(BaseModel): | ||
minAge: int # 닫힌 구간 | ||
maxAge: int # 닫힌 구간 | ||
count: int | ||
|
||
|
||
|
||
class PartyChartDataPoint(BaseModel): | ||
party: str | ||
count: int | ||
|
||
|
||
T = TypeVar("T", SexChartDataPoint, AgeChartDataPoint, PartyChartDataPoint) | ||
|
||
class ChartData(BaseModel, Generic[T]): | ||
data: list[T] | ||
|
||
|
||
# ============================================== | ||
# = Scrap Result Data Types = | ||
# ============================================== | ||
class CouncilType(StrEnum): | ||
local_council = "local_council" | ||
national_council = "national_council" | ||
metropolitan_council = "metropolitan_council" | ||
local_leader= "local_leader" | ||
local_leader = "local_leader" | ||
metro_leader = "metro_leader" | ||
|
||
|
||
class CouncilInfo(BaseModel): | ||
name : str | ||
name: str | ||
party: str | ||
|
||
|
||
class ScrapResult(BaseModel): | ||
council_id : str | ||
council_type : CouncilType | ||
councilers : list[CouncilInfo] | ||
council_id: str | ||
council_type: CouncilType | ||
councilers: list[CouncilInfo] |
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,39 @@ | ||
from fastapi import APIRouter | ||
from model import MongoDB, CommonInfo | ||
|
||
router = APIRouter(prefix="/localCouncil", tags=["localCouncil"]) | ||
|
||
|
||
@router.get("/regionInfo") | ||
async def getRegionInfo() -> list[CommonInfo.RegionInfo]: | ||
regions = [] | ||
async for metro in MongoDB.client.district_db.get_collection( | ||
"metro_district" | ||
).find(): | ||
local_districts = [] | ||
async for local in MongoDB.client.district_db.get_collection( | ||
"local_district" | ||
).find({"metro_id": metro["metro_id"]}): | ||
local_districts.append({"name": local["name_ko"], "id": local["local_id"]}) | ||
regions.append( | ||
CommonInfo.RegionInfo.model_validate( | ||
{ | ||
"name": metro["name_ko"], | ||
"id": metro["metro_id"], | ||
"local": local_districts, | ||
} | ||
) | ||
) | ||
return regions | ||
|
||
|
||
@router.get("/partyInfo") | ||
async def getPartyInfo() -> list[CommonInfo.PartyInfo]: | ||
parties = [] | ||
async for party in MongoDB.client.district_db.get_collection("party").find(): | ||
parties.append( | ||
CommonInfo.PartyInfo.model_validate( | ||
{"name": party["name"], "color": party["color"]} | ||
) | ||
) | ||
return parties |
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,37 +1,115 @@ | ||
from fastapi import APIRouter | ||
from model import BasicResponse, MongoDB, ScrapResult | ||
from utils import diversity | ||
from typing import TypeVar | ||
|
||
from model.ResponseType import * | ||
|
||
router = APIRouter(prefix="/localCouncil", tags=["localCouncil"]) | ||
|
||
@router.get("/regionInfo", response_model=RegionInfo) | ||
async def getRegionInfo(): | ||
try: | ||
return [] | ||
except Exception as e: | ||
print(e) | ||
return [] | ||
|
||
@router.get("/partyInfo", response_model=PartyInfo) | ||
async def getPartyInfo(): | ||
try: | ||
return [] | ||
except Exception as e: | ||
print(e) | ||
return [] | ||
|
||
@router.get("/template-data/{metroId}/{localId}/{factor}", response_model=Diversity) | ||
async def getTemplateData(metroId: int, localId: int, factor: str): | ||
try: | ||
return [] | ||
except Exception as e: | ||
print(e) | ||
return [] | ||
|
||
@router.get("/chart-data/{metroId}/{localId}/{factor}", response_model=ChartResponse) | ||
async def getTemplateData(metroId: int, localId: int, factor: str): | ||
try: | ||
return [] | ||
except Exception as e: | ||
print(e) | ||
return [] | ||
|
||
router = APIRouter("/localCouncil", tags=["localCouncil"]) | ||
|
||
AGE_STAIR = 10 | ||
|
||
|
||
@router.get("/template-data/{metroId}/{localId}") | ||
async def getLocalTemplateData( | ||
metroId: int, localId: int, factor: ScrapResult.FactorType | ||
) -> BasicResponse.ErrorResponse | ScrapResult.SexTemplateData | ScrapResult.AgeTemplateData | ScrapResult.PartyTemplateData: | ||
if ( | ||
await MongoDB.client.district_db["local_district"].find_one( | ||
{"local_id": localId, "metro_id": metroId} | ||
) | ||
is None | ||
): | ||
return BasicResponse.ErrorResponse.model_validate( | ||
{ | ||
"error": "RegionCodeError", | ||
"code": BasicResponse.REGION_CODE_ERR, | ||
"message": f"No local district with metroId {metroId} and localId {localId}.", | ||
} | ||
) | ||
|
||
councilors = MongoDB.client.council_db["local_councilor"].find( | ||
{"local_id": localId} | ||
) | ||
|
||
match factor: | ||
case ScrapResult.FactorType.sex: | ||
sex_list = [councilor["sex"] async for councilor in councilors] | ||
sex_diversity_index = diversity.gini_simpson(sex_list) | ||
return ScrapResult.SexTemplateData.model_validate( | ||
{"sexDiversityIndex": sex_diversity_index} | ||
) | ||
|
||
case ScrapResult.FactorType.age: | ||
age_list = [councilor["age"] async for councilor in councilors] | ||
age_diversity_index = diversity.gini_simpson(age_list, stair=AGE_STAIR) | ||
return ScrapResult.AgeTemplateData.model_validate( | ||
{"ageDiversityIndex": age_diversity_index} | ||
) | ||
|
||
case ScrapResult.FactorType.party: | ||
party_list = [councilor["party"] async for councilor in councilors] | ||
party_diversity_index = diversity.gini_simpson(party_list) | ||
return ScrapResult.PartyTemplateData.model_validate( | ||
{"partyDiversityIndex": party_diversity_index} | ||
) | ||
|
||
|
||
T = TypeVar("T", ScrapResult.SexChartData, ScrapResult.AgeChartData, ScrapResult.PartyChartData) | ||
|
||
@router.get("/chart-data/{metroId}/{localId}") | ||
async def getLocalChartData( | ||
metroId: int, localId: int, factor: ScrapResult.FactorType | ||
) -> BasicResponse.ErrorResponse | ScrapResult.ChartData[T]: | ||
if ( | ||
await MongoDB.client.district_db["local_district"].find_one( | ||
{"local_id": localId, "metro_id": metroId} | ||
) | ||
is None | ||
): | ||
return BasicResponse.ErrorResponse.model_validate( | ||
{ | ||
"error": "RegionCodeError", | ||
"code": BasicResponse.REGION_CODE_ERR, | ||
"message": f"No local district with metroId {metroId} and localId {localId}.", | ||
} | ||
) | ||
|
||
councilors = MongoDB.client.council_db["local_councilor"].find( | ||
{"local_id": localId} | ||
) | ||
|
||
match factor: | ||
case ScrapResult.FactorType.sex: | ||
sex_list = [councilor["sex"] async for councilor in councilors] | ||
sex_count = diversity.count(sex_list) | ||
return ScrapResult.ChartData[ScrapResult.SexChartDataPoint].model_validate( | ||
{"data": [{"sex": sex, "count": sex_count[sex]} for sex in sex_count]} | ||
) | ||
|
||
case ScrapResult.FactorType.age: | ||
age_list = [councilor["age"] async for councilor in councilors] | ||
age_count = diversity.count(age_list, stair=AGE_STAIR) | ||
return ScrapResult.ChartData[ScrapResult.AgeChartDataPoint].model_validate( | ||
{ | ||
"data": [ | ||
{ | ||
"minAge": age, | ||
"maxAge": age + AGE_STAIR - 1, | ||
"count": age_count[age], | ||
} | ||
for age in age_count | ||
] | ||
} | ||
) | ||
|
||
case ScrapResult.FactorType.party: | ||
party_list = [councilor["party"] async for councilor in councilors] | ||
party_count = diversity.count(party_list) | ||
return ScrapResult.ChartData[ScrapResult.PartyChartDataPoint].model_validate( | ||
{ | ||
"data": [ | ||
{"party": party, "count": party_count[party]} | ||
for party in party_count | ||
] | ||
} | ||
) |
Oops, something went wrong.