General bug fixes and clean up. Starting on a better version 2 of the CRUD endpoints.

This commit is contained in:
Scott Idem
2024-04-23 16:19:00 -04:00
parent dd527378bb
commit 4c87e4a5fc
6 changed files with 1497 additions and 8 deletions

View File

@@ -1,6 +1,7 @@
import datetime, json, time
#from datetime import datetime, time, timedelta
from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, Response, status
from fastapi.responses import FileResponse
from pydantic import BaseModel, EmailStr, Field
from typing import Dict, List, Optional, Set, Union
@@ -65,7 +66,8 @@ from app.models.user_role_models import *
from app.models.e_stripe_models import *
obj_type_li = {}
obj_type_kv_li = {} # New 2024-04-23
obj_type_li = {} # Old...
#obj_type_li['cfg_flask'] = {'table_name': 'cfg_flask', 'base_name': Cfg_Flask_Base}
@@ -178,7 +180,7 @@ obj_type_li['post'] = {'table_name': 'v_post', 'tbl_name_update': 'post', 'base_
obj_type_li['post_comment'] = {'table_name': 'v_post_comment', 'tbl_name_update': 'post_comment', 'base_name': Post_Comment_Base} # NOTE check view name: *_detail?
obj_type_li['product'] = {'table_name': 'v_product', 'tbl_name_update': 'product', 'base_name': Product_Base}
obj_type_li['sponsorship'] = {'table_name': 'v_sponsorship', 'tbl_name_update': 'sponsorship', 'base_name': Sponsorship_Base} # NOTE check view name: *_detail?
obj_type_li['sponsorship'] = {'table_name': 'v_sponsorship', 'tbl_name_update': 'sponsorship', 'base_name': Sponsorship_Base, 'tbl': 'v_sponsorship', 'tbl': 'v_sponsorship', 'mdl': Sponsorship_Base } # NOTE check view name: *_detail?
obj_type_li['sponsorship_cfg'] = {'table_name': 'v_sponsorship_cfg', 'tbl_name_update': 'sponsorship_cfg', 'base_name': Sponsorship_Cfg_Base}
#obj_type_li['stripe_customer'] = {'table_name': 'stripe_customer', 'tbl_name_update': 'stripe_customer', 'base_name': Stripe_Customer_Base}
@@ -230,6 +232,9 @@ async def get_obj_li(
# Get the "json" param from the query string. This is a JSON formatted string of the data to be inserted.
jp: Optional[Union[str, None]] = None,
file_type: str = 'CSV', # CSV, Excel
return_file: Optional[bool] = False,
commons: Common_Route_Params = Depends(common_route_params),
):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
@@ -396,6 +401,7 @@ async def get_obj_li(
if sql_result:
if isinstance(sql_result, list):
log.setLevel(logging.DEBUG)
resp_data_li = []
for record in sql_result:
if base_name:
@@ -405,7 +411,91 @@ async def get_obj_li(
log.warning('base_name model was not found. Returning raw data.')
resp_data = record
resp_data_li.append(resp_data)
return mk_resp(data=resp_data_li, response=commons.response)
column_name_li = list(sql_result[0].keys()) # This should be the same for all records in the list.
if return_file:
log.setLevel(logging.DEBUG)
# We want to handle any field that has a suffix of _json. It should be expanded into a list of fields that are prefixed with the original field name minus _json.
# This will also allow us to export the data to a CSV or Excel file with the correct column names.
# additional_json_field_list_for_export = []
new_resp_data_li = []
for record in resp_data_li:
new_record = record.copy()
for field_name in record.keys():
field_value = record[field_name]
if field_name.endswith('li_json') and record[field_name]:
log.info(f'Found a field that ends with li_json: {field_name}')
log.info(f'Field value is a list??: {field_value}')
# field_value = json.loads(record[key]) # Convert the string to a list of dictionaries
# Example JSON data: {'facebook': 'https://www.facebook.com/example', 'twitter': 'https://twitter.com/example', 'instagram': 'https://www.instagram.com/example/', 'linkedin': 'https://www.linkedin.com/school/example', 'org': 'https://example.com/'}
# Example new fields: social__facebook, social__twitter, social__instagram, social__linkedin, social__org
if isinstance(field_value, list):
# Loop through the list of dictionaries
log.info(f'Field value is a list: {field_value}')
for item in field_value:
# item = json.loads(item) # Convert the string to a dictionary
for key, value in item.items():
new_field_name = field_name[:-8]+'__'+key
new_record[new_field_name] = value
else:
# Loop through key value pairs in the dictionary
log.info(f'Field value is a dict: {field_value}')
for key, value in field_value.items():
new_field_name = field_name[:-8]+'__'+key
new_record[new_field_name] = value
# Create a new field for each and value to the record
# new_field_name = key[:-8]+'__cust_li'
# new_record[new_field_name] = record[key]
new_record.pop(field_name) # Remove the original field
elif field_name.endswith('_json') and record[field_name]:
log.info(f'Found a field that ends with _json: {field_name}')
log.info(f'Field value is a dict???: {field_value}')
for key, value in field_value.items():
new_field_name = field_name[:-5]+'__'+key
new_record[new_field_name] = value
new_record.pop(field_name) # Remove the original field
elif field_name.endswith('li_json') or field_name.endswith('_json'):
log.info(f'Found a field that ends with li_json or _json but no value: {field_name}')
new_record.pop(field_name) # Remove the original field
new_resp_data_li.append(new_record)
datetime_format='%Y-%m-%d_%H%M'
# current_datetime = datetime.datetime.now() # Servers timezone (Eastern)
current_datetime_utc = datetime.datetime.utcnow() # UTC timezone
current_datetime_utc = current_datetime_utc.strftime(datetime_format)
filename = f'{obj_name}_list_{current_datetime_utc}'
if file_type == 'CSV':
filename_w_ext = filename+'.csv'
elif file_type == 'Excel':
filename_w_ext = filename+'.xlsx'
log.setLevel(logging.INFO)
if result := create_export_file(data_dict_list=new_resp_data_li, column_name_li=[], subdir_path=obj_name, filename=filename, rm_id=True, export_type=file_type):
log.info(f'Export file created and saved: {result}')
else:
log.error('Something went wrong while creating or saving the export file')
tmp_file_path = result
log.info(f'Filename: {filename_w_ext}')
if full_tmp_path := return_full_tmp_path(full_tmp_path=tmp_file_path):
return FileResponse(path=full_tmp_path, filename=filename_w_ext)
else:
return mk_resp(data=resp_data_li, response=commons.response)
else:
status_message='Not Implemented (sort of). Attempted to process this request. Got a SQL result, but the returned data was unexpected.'
@@ -1227,3 +1317,22 @@ def delete_obj_template(
else:
log.debug(sql_result)
return mk_resp(data=False, status_code=404, response=response)
# New dynamic API CRUD endpoint
# The POST data should be JSON formatted
# @router.post('/query')
# def query(
# # qry JSON should contain these properties:
# # list: for_obj_type, for_obj_id, tbl_view_name, base_name
# # id: obj_id, tbl_view_name, base_name
# qry: str,
# commons: Common_Route_Params = Depends(common_route_params),
# ):
# log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
# log.debug(locals())
# import urllib

1180
app/routers/api_crud_v2.py Normal file

File diff suppressed because it is too large Load Diff