Build a Python FastAPI server that provides endpoints for CRUD operations on a PostgreSQL database. Use SQLAlchemy for ORM and ensure proper validation of incoming data.
PLAINFORMAT
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List
import models
from database import SessionLocal, engine

app = FastAPI()

models.Base.metadata.create_all(bind=engine)

class ItemCreate(BaseModel):
    name: str
    description: str

class ItemUpdate(BaseModel):
    id: int
    name: str
    description: str

@app.post("/items/", response_model=models.Item)
def create_item(item: ItemCreate):
    db = SessionLocal()
    db_item = models.Item(name=item.name, description=item.description)
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    return db_item

@app.get("/items/{item_id}", response_model=models.Item)
def read_item(item_id: int):
    db = SessionLocal()
    item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")
    return item

@app.get("/items/", response_model=List[models.Item])
def read_items():
    db = SessionLocal()
    items = db.query(models.Item).all()
    return items

@app.put("/items/{item_id}", response_model=models.Item)
def update_item(item_id: int, item: ItemUpdate):
    db = SessionLocal()
    db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if not db_item:
        raise HTTPException(status_code=404, detail="Item not found")
    
    db_item.name = item.name
    db_item.description = item.description
    db.commit()
    return db_item

@app.delete("/items/{item_id}")
def delete_item(item_id: int):
    db = SessionLocal()
    item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    db.delete(item)
    db.commit()
    return {"detail": "Item deleted"}

# database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "postgresql://username:password@localhost/dbname"

engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

# models.py
from sqlalchemy import Column, Integer, String
from database import Base

class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    description = Column(String)