Add download api (CSV)

This commit is contained in:
phil 2024-04-04 00:35:18 +05:30
parent 8b7081df67
commit d09099acac
2 changed files with 80 additions and 1 deletions

77
src/gisaf/api/download.py Normal file
View file

@ -0,0 +1,77 @@
import logging
import io
from typing import Annotated
from fastapi import (Depends, APIRouter, HTTPException, status, Response)
from fastapi.responses import FileResponse, StreamingResponse
from sqlmodel import select
from sqlalchemy.orm import selectinload, joinedload
from gisaf.database import pandas_query, fastapi_db_session as db_session
from gisaf.models.geo_models_base import GeoModel, PlottableModel
from gisaf.security import (
Token, authenticate_user, get_current_active_user, create_access_token,
)
from gisaf.models.authentication import (User, UserRead, Role, RoleRead)
from gisaf.registry import registry, NotInRegistry
logger = logging.getLogger(__name__)
api = APIRouter(
tags=["download"],
# dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
@api.get('/csv/{store}/{model_id}/{value}/{resample}',
responses={
200: {
"content": {
"text/csv": {}
}
}
})
async def download_csv(
store: str, model_id: int, value: str, resample: str,
db_session: db_session,
user: Annotated[UserRead, Depends(get_current_active_user)]
) -> StreamingResponse:
try:
store_record = registry.stores.loc[store]
model: type[GeoModel] = store_record.model
values_model = registry.values_for_model[model][0]
except KeyError:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
## Check if there's a custom getter
custom_getter = getattr(values_model, f'get_{value}', None)
if custom_getter:
df = await custom_getter(model_id)
else:
df = await values_model.get_as_dataframe(model_id=model_id, with_only_columns=[value])
if len(df) == 0:
raise HTTPException(status.HTTP_204_NO_CONTENT)
if resample and resample != '0':
value_defs = [v for v in values_model.values if v['name'] == value]
if len(value_defs) > 0 and 'agg' in value_defs[0]:
resampling_method = value_defs[0]['agg']
else:
resampling_method = 'mean'
df = df.resample(resample).agg(resampling_method)
if len(df) > 0:
df.reset_index(inplace=True)
query = select(model).where(model.id == model_id).options(
*(joinedload(jt) for jt in model.selectinload()))
response = await db_session.exec(query)
item = response.one()
filename = f'"{item.caption}-{value}-{resample}.csv"'
filename = f'{item.__class__.__name__}-{value}-{resample}.csv'
stream = io.StringIO()
df.reset_index().to_csv(stream,
index=False,
date_format='%d/%m/%Y %H:%M',
float_format=values_model.float_format)
response = Response(stream.getvalue(),
headers={
'Content-Disposition': f"attachment; filename={filename}"
})
return response