mirror of
https://github.com/sstent/foodplanner.git
synced 2026-01-25 11:11:36 +00:00
fixing db tables and onplace upgrde
This commit is contained in:
@@ -0,0 +1,76 @@
|
|||||||
|
"""Data migration to convert serving_size to float
|
||||||
|
|
||||||
|
Revision ID: 13939361fc35
|
||||||
|
Revises: a11a3921f528
|
||||||
|
Create Date: 2025-10-01 23:44:34.144506
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = '13939361fc35'
|
||||||
|
down_revision: Union[str, None] = 'a11a3921f528'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""
|
||||||
|
Data migration to convert existing string-based 'serving_size' values to floats.
|
||||||
|
This version uses a session to iterate through the data, providing more robust error handling.
|
||||||
|
"""
|
||||||
|
bind = op.get_bind()
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
Session = sessionmaker(bind=bind)
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
# Define a simple table structure for our purpose
|
||||||
|
food_table = sa.Table('foods', sa.MetaData(),
|
||||||
|
sa.Column('id', sa.Integer, primary_key=True),
|
||||||
|
sa.Column('name', sa.String),
|
||||||
|
sa.Column('serving_size', sa.String) # Treat it as String to be safe
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
foods_to_update = session.query(food_table).all()
|
||||||
|
updated_count = 0
|
||||||
|
|
||||||
|
for food in foods_to_update:
|
||||||
|
# Check if serving_size is a string and needs conversion
|
||||||
|
if isinstance(food.serving_size, str):
|
||||||
|
try:
|
||||||
|
new_size = float(food.serving_size)
|
||||||
|
# Use session.execute for the update
|
||||||
|
session.execute(
|
||||||
|
food_table.update().
|
||||||
|
where(food_table.c.id == food.id).
|
||||||
|
values(serving_size=new_size)
|
||||||
|
)
|
||||||
|
updated_count += 1
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
print(f"Could not convert serving_size for Food ID {food.id} (Name: {food.name}). Value: '{food.serving_size}'")
|
||||||
|
|
||||||
|
if updated_count > 0:
|
||||||
|
session.commit()
|
||||||
|
print(f"Successfully converted {updated_count} food items.")
|
||||||
|
else:
|
||||||
|
print("No food items required an update.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An error occurred during the data migration: {e}")
|
||||||
|
session.rollback()
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
# A downgrade for this data migration is not practical as it would require
|
||||||
|
# converting floats back to strings, which could lead to loss of precision.
|
||||||
|
# It is better to back up the database before upgrading.
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
"""Ensure serving_size column is Float
|
||||||
|
|
||||||
|
Revision ID: d0c142fbf0b0
|
||||||
|
Revises: 13939361fc35
|
||||||
|
Create Date: 2025-10-02 00:27:05.400224
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = 'd0c142fbf0b0'
|
||||||
|
down_revision: Union[str, None] = '13939361fc35'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('foods', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('serving_size',
|
||||||
|
existing_type=sa.VARCHAR(),
|
||||||
|
type_=sa.Float(),
|
||||||
|
existing_nullable=True)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('foods', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('serving_size',
|
||||||
|
existing_type=sa.Float(),
|
||||||
|
type_=sa.VARCHAR(),
|
||||||
|
existing_nullable=True)
|
||||||
|
# ### end Alembic commands ###
|
||||||
@@ -14,23 +14,11 @@ router = APIRouter()
|
|||||||
# Meals tab
|
# Meals tab
|
||||||
@router.get("/meals", response_class=HTMLResponse)
|
@router.get("/meals", response_class=HTMLResponse)
|
||||||
async def meals_page(request: Request, db: Session = Depends(get_db)):
|
async def meals_page(request: Request, db: Session = Depends(get_db)):
|
||||||
try:
|
from sqlalchemy.orm import joinedload
|
||||||
from sqlalchemy.orm import joinedload
|
meals = db.query(Meal).options(joinedload(Meal.meal_foods).joinedload(MealFood.food)).all()
|
||||||
logging.info("DEBUG: Starting meals query with eager loading")
|
foods = db.query(Food).all()
|
||||||
meals = db.query(Meal).options(joinedload(Meal.meal_foods).joinedload(MealFood.food)).all()
|
return templates.TemplateResponse("meals.html",
|
||||||
logging.info(f"DEBUG: Retrieved {len(meals)} meals")
|
{"request": request, "meals": meals, "foods": foods})
|
||||||
foods = db.query(Food).all()
|
|
||||||
logging.info(f"DEBUG: Retrieved {len(foods)} foods")
|
|
||||||
|
|
||||||
# Test template rendering with a simple test
|
|
||||||
logging.info("DEBUG: Testing template rendering...")
|
|
||||||
test_data = {"request": request, "meals": meals, "foods": foods}
|
|
||||||
return templates.TemplateResponse("meals.html", test_data)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"DEBUG: Error in meals_page: {str(e)}", exc_info=True)
|
|
||||||
# Return a simple error response for debugging
|
|
||||||
return HTMLResponse(f"<h1>Error in meals page</h1><pre>{str(e)}</pre><pre>{type(e).__name__}</pre>")
|
|
||||||
|
|
||||||
@router.post("/meals/upload")
|
@router.post("/meals/upload")
|
||||||
async def bulk_upload_meals(file: UploadFile = File(...), db: Session = Depends(get_db)):
|
async def bulk_upload_meals(file: UploadFile = File(...), db: Session = Depends(get_db)):
|
||||||
|
|||||||
7
main.py
7
main.py
@@ -253,12 +253,11 @@ def run_migrations():
|
|||||||
|
|
||||||
if has_foods and (not has_alembic_version or not alembic_version_has_content):
|
if has_foods and (not has_alembic_version or not alembic_version_has_content):
|
||||||
logging.info("DEBUG: Existing database detected. Stamping with initial migration.")
|
logging.info("DEBUG: Existing database detected. Stamping with initial migration.")
|
||||||
command.stamp(alembic_cfg, "head")
|
# Stamp with the specific initial migration that creates all tables
|
||||||
|
command.stamp(alembic_cfg, "cf94fca21104")
|
||||||
logging.info("DEBUG: Database stamped successfully.")
|
logging.info("DEBUG: Database stamped successfully.")
|
||||||
else:
|
|
||||||
logging.info("DEBUG: No stamping needed or fresh database.")
|
|
||||||
|
|
||||||
# Now, run upgrades
|
# Now, run upgrades to bring the database to the latest version
|
||||||
logging.info("DEBUG: Running alembic upgrade...")
|
logging.info("DEBUG: Running alembic upgrade...")
|
||||||
command.upgrade(alembic_cfg, "head")
|
command.upgrade(alembic_cfg, "head")
|
||||||
logging.info("DEBUG: Database migrations run successfully.")
|
logging.info("DEBUG: Database migrations run successfully.")
|
||||||
|
|||||||
Reference in New Issue
Block a user