Fix internal server error when creating tasks and other endpoints
This commit is contained in:
parent
73d7a71140
commit
d48cd52fb7
@ -22,8 +22,8 @@ def upgrade():
|
|||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('title', sa.String(length=100), nullable=False),
|
sa.Column('title', sa.String(length=100), nullable=False),
|
||||||
sa.Column('description', sa.Text(), nullable=True),
|
sa.Column('description', sa.Text(), nullable=True),
|
||||||
sa.Column('priority', sa.Enum('LOW', 'MEDIUM', 'HIGH', name='taskpriority'), default='MEDIUM'),
|
sa.Column('priority', sa.Enum('low', 'medium', 'high', name='taskpriority'), default='medium'),
|
||||||
sa.Column('status', sa.Enum('TODO', 'IN_PROGRESS', 'DONE', name='taskstatus'), default='TODO'),
|
sa.Column('status', sa.Enum('todo', 'in_progress', 'done', name='taskstatus'), default='todo'),
|
||||||
sa.Column('due_date', sa.DateTime(), nullable=True),
|
sa.Column('due_date', sa.DateTime(), nullable=True),
|
||||||
sa.Column('completed', sa.Boolean(), default=False),
|
sa.Column('completed', sa.Boolean(), default=False),
|
||||||
sa.Column('created_at', sa.DateTime(), default=sa.func.now()),
|
sa.Column('created_at', sa.DateTime(), default=sa.func.now()),
|
||||||
|
@ -5,7 +5,7 @@ from typing import Any, Dict, List, Optional, Union
|
|||||||
from pydantic import AnyHttpUrl, field_validator
|
from pydantic import AnyHttpUrl, field_validator
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
DB_DIR = Path("/app") / "storage" / "db"
|
DB_DIR = Path("/app/storage/db")
|
||||||
DB_DIR.mkdir(parents=True, exist_ok=True)
|
DB_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
@ -29,8 +29,9 @@ class Settings(BaseSettings):
|
|||||||
# Database configuration
|
# Database configuration
|
||||||
SQLALCHEMY_DATABASE_URL: str = f"sqlite:///{DB_DIR}/db.sqlite"
|
SQLALCHEMY_DATABASE_URL: str = f"sqlite:///{DB_DIR}/db.sqlite"
|
||||||
|
|
||||||
class Config:
|
model_config = {
|
||||||
case_sensitive = True
|
"case_sensitive": True
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
@ -45,7 +45,11 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
|
|||||||
if isinstance(obj_in, dict):
|
if isinstance(obj_in, dict):
|
||||||
update_data = obj_in
|
update_data = obj_in
|
||||||
else:
|
else:
|
||||||
update_data = obj_in.model_dump(exclude_unset=True)
|
# Handle both Pydantic v1 and v2
|
||||||
|
if hasattr(obj_in, "model_dump"):
|
||||||
|
update_data = obj_in.model_dump(exclude_unset=True)
|
||||||
|
else:
|
||||||
|
update_data = obj_in.dict(exclude_unset=True)
|
||||||
for field in obj_data:
|
for field in obj_data:
|
||||||
if field in update_data:
|
if field in update_data:
|
||||||
setattr(db_obj, field, update_data[field])
|
setattr(db_obj, field, update_data[field])
|
||||||
@ -55,7 +59,8 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
|
|||||||
return db_obj
|
return db_obj
|
||||||
|
|
||||||
def remove(self, db: Session, *, id: int) -> ModelType:
|
def remove(self, db: Session, *, id: int) -> ModelType:
|
||||||
obj = db.query(self.model).get(id)
|
obj = db.query(self.model).filter(self.model.id == id).first()
|
||||||
db.delete(obj)
|
if obj:
|
||||||
db.commit()
|
db.delete(obj)
|
||||||
|
db.commit()
|
||||||
return obj
|
return obj
|
44
app/db/init_db.py
Normal file
44
app/db/init_db.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from sqlalchemy import text
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.db.session import engine
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
|
||||||
|
def init_db() -> None:
|
||||||
|
"""Initialize database with required tables and data."""
|
||||||
|
|
||||||
|
# Ensure database directory exists
|
||||||
|
Path(settings.DB_DIR).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Try to connect to check if the database is accessible
|
||||||
|
with engine.connect() as conn:
|
||||||
|
try:
|
||||||
|
conn.execute(text("SELECT 1"))
|
||||||
|
print("Database connection successful")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Database connection error: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Run alembic upgrade to create tables
|
||||||
|
try:
|
||||||
|
# Get the project root directory (where alembic.ini is located)
|
||||||
|
project_root = Path(__file__).parent.parent.parent.absolute()
|
||||||
|
|
||||||
|
# Change to project root directory and run alembic
|
||||||
|
os.chdir(project_root)
|
||||||
|
subprocess.run(["alembic", "upgrade", "head"], check=True)
|
||||||
|
print("Database migration successful")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Database migration error: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
print("Database initialized successfully")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
init_db()
|
@ -33,8 +33,9 @@ class TaskInDBBase(TaskBase):
|
|||||||
created_at: datetime
|
created_at: datetime
|
||||||
updated_at: datetime
|
updated_at: datetime
|
||||||
|
|
||||||
class Config:
|
model_config = {
|
||||||
from_attributes = True
|
"from_attributes": True
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Task(TaskInDBBase):
|
class Task(TaskInDBBase):
|
||||||
|
54
main.py
54
main.py
@ -1,8 +1,25 @@
|
|||||||
from fastapi import FastAPI
|
import sys
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add project root to Python path for imports in alembic migrations
|
||||||
|
project_root = Path(__file__).parent.absolute()
|
||||||
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
from app.api.routers import api_router
|
from app.api.routers import api_router
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
from app.db import init_db
|
||||||
|
|
||||||
|
# Initialize the database on startup
|
||||||
|
try:
|
||||||
|
init_db.init_db()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error initializing database: {e}")
|
||||||
|
# Continue with app startup even if DB init fails, to allow debugging
|
||||||
|
|
||||||
app = FastAPI(title=settings.PROJECT_NAME)
|
app = FastAPI(title=settings.PROJECT_NAME)
|
||||||
|
|
||||||
@ -15,6 +32,14 @@ app.add_middleware(
|
|||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add exception handlers for better error reporting
|
||||||
|
@app.exception_handler(Exception)
|
||||||
|
async def validation_exception_handler(request: Request, exc: Exception):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=500,
|
||||||
|
content={"detail": f"Internal Server Error: {str(exc)}"},
|
||||||
|
)
|
||||||
|
|
||||||
app.include_router(api_router)
|
app.include_router(api_router)
|
||||||
|
|
||||||
|
|
||||||
@ -23,4 +48,29 @@ def health_check():
|
|||||||
"""
|
"""
|
||||||
Health check endpoint to verify the application is running correctly
|
Health check endpoint to verify the application is running correctly
|
||||||
"""
|
"""
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/db-test", tags=["health"])
|
||||||
|
def test_db_connection():
|
||||||
|
"""
|
||||||
|
Test database connection and table creation
|
||||||
|
"""
|
||||||
|
from sqlalchemy import text
|
||||||
|
from app.db.session import engine
|
||||||
|
|
||||||
|
try:
|
||||||
|
with engine.connect() as conn:
|
||||||
|
# Try to select from the task table to verify it exists
|
||||||
|
result = conn.execute(text("SELECT COUNT(*) FROM task")).scalar()
|
||||||
|
return {
|
||||||
|
"status": "ok",
|
||||||
|
"connection": "successful",
|
||||||
|
"task_count": result
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {
|
||||||
|
"status": "error",
|
||||||
|
"connection": "failed",
|
||||||
|
"error": str(e)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user