Bootcamp i FastAPI-backendudvikling · Lektion

CRUD-operationer med SQLAlchemy

Implementér Create-, Read-, Update- og Delete-operationer til Deres API-endpoints ved hjælp af SQLAlchemy ORM.

Lektion 3 af 413 trin

CRUD-operationer med SQLAlchemy er en gratis Bootcamp i FastAPI-backendudvikling-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Bootcamp i FastAPI-backendudvikling, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Bootcamp i FastAPI-backendudvikling-kurset indeholder 4 lektioner i alt.

CRUD-handlinger: Kernen

Velkommen til lektion 3! I dag lærer du at mestre CRUD-handlinger ved hjælp af FastAPI og SQLAlchemy. CRUD står for:

  • Create: Tilføjelse af nye data.
  • Read: Hentning af eksisterende data.
  • Update: Ændring af eksisterende data.
  • Delete: Fjernelse af data.

Disse fire handlinger er grundlaget for næsten alle applikationer, der interagerer med en database.

Opsætning: Modeller og session

Før du går i gang med CRUD, skal du konfigurere din SQLAlchemy-model og dine Pydantic-skemaer. Du bruger en SQLite-database i hukommelsen i de kørbare eksempler.

Først din SQLAlchemy-Todo-model, der repræsenterer en opgave:

from sqlalchemy import Column, Integer, String, Boolean
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Todo(Base):
    __tablename__ = "todos"
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    description = Column(String, default="")
    completed = Column(Boolean, default=False)

Og Pydantic-skemaer til forespørgsel/svar:

from pydantic import BaseModel

class TodoCreate(BaseModel):
    title: str
    description: str = ""
    completed: bool = False

class TodoResponse(TodoCreate):
    id: int

    class Config:
        orm_mode = True

Databasesession i FastAPI

I FastAPI håndterer du databasesessioner ved hjælp af afhængigheder. Det sikrer, at hver forespørgsel får en ny session, og at den lukkes korrekt.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

Denne get_db-funktion injiceres i vores FastAPI-slutpunkter.

Opret: FastAPI-slutpunkt

Hvis du vil oprette et nyt element, bruger du en POST-forespørgsel. Slutpunktet modtager data via en Pydantic-model og bruger SQLAlchemy til at føje dem til databasen.

from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session

# ... (imports for Base, Todo, TodoCreate, TodoResponse, get_db, engine)

app = FastAPI()
Base.metadata.create_all(bind=engine) # Create tables

@app.post("/todos/", response_model=TodoResponse)
def create_todo(todo: TodoCreate, db: Session = Depends(get_db)):
    db_todo = Todo(title=todo.title, description=todo.description, completed=todo.completed)
    db.add(db_todo)
    db.commit()
    db.refresh(db_todo) # Refresh to get ID and updated fields
    return db_todo

Kaldet db.refresh() opdaterer vores db_todo-objekt med værdier, der er genereret af databasen, for eksempel id.

Opret: SQLAlchemy-demo

Lad os se SQLAlchemys trin til at oprette data i praksis. Dette kørbare script føjer en ny todo til vores database i hukommelsen.

from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 1. Setup Database and Model
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class Todo(Base):
    __tablename__ = "todos"
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    description = Column(String, default="")
    completed = Column(Boolean, default=False)

# 2. Create Tables
Base.metadata.create_all(bind=engine)

# 3. Create a Session
db = SessionLocal()

# 4. Create Operation (C)
print("--- Creating a new Todo ---")
new_todo = Todo(title="Learn FastAPI", description="Complete CoddyKit lesson", completed=False)
db.add(new_todo)
db.commit()
db.refresh(new_todo)
print(f"Created Todo: ID={new_todo.id}, Title='{new_todo.title}'")

# 5. Close Session
db.close()

Læs: FastAPI-slutpunkter

Hvis du vil læse data, bruger du GET-forespørgsler. Du har to slutpunkter: ét til at hente alle todo-elementer og ét til at hente et enkelt todo-element ud fra dets ID.

# ... (FastAPI app, imports, get_db, models)

@app.get("/todos/", response_model=list[TodoResponse])
def read_todos(db: Session = Depends(get_db)):
    todos = db.query(Todo).all()
    return todos

@app.get("/todos/{todo_id}", response_model=TodoResponse)
def read_todo(todo_id: int, db: Session = Depends(get_db)):
    todo = db.query(Todo).filter(Todo.id == todo_id).first()
    if todo is None:
        raise HTTPException(status_code=404, detail="Todo not found")
    return todo

Du bruger .all() til at hente en liste og .first() til at hente et enkelt element. Husk at håndtere tilfælde, hvor et element ikke findes!

Læs: SQLAlchemy-demo

Lad os køre en demonstration af handlingen Læs. Først opretter du nogle todo-elementer, derefter henter du dem alle og til sidst et bestemt element ud fra dets ID.

from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# Setup Database and Model (same as before)
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class Todo(Base):
    __tablename__ = "todos"
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    description = Column(String, default="")
    completed = Column(Boolean, default=False)

Base.metadata.create_all(bind=engine)
db = SessionLocal()

# Create some initial Todos for reading
todo1 = Todo(title="Buy groceries")
todo2 = Todo(title="Walk the dog")
db.add_all([todo1, todo2])
db.commit()
db.refresh(todo1)
db.refresh(todo2)
print(f"Created Todos: {todo1.id}, {todo2.id}\n")

# Read Operation (R)
print("--- Reading all Todos ---")
all_todos = db.query(Todo).all()
for t in all_todos:
    print(f"ID={t.id}, Title='{t.title}'")

print("\n--- Reading a specific Todo (ID 1) ---")
specific_todo = db.query(Todo).filter(Todo.id == 1).first()
if specific_todo:
    print(f"Found Todo: ID={specific_todo.id}, Title='{specific_todo.title}'")
else:
    print("Todo with ID 1 not found.")

print("\n--- Reading a non-existent Todo (ID 99) ---")
non_existent_todo = db.query(Todo).filter(Todo.id == 99).first()
if non_existent_todo:
    print(f"Found Todo: ID={non_existent_todo.id}")
else:
    print("Todo with ID 99 not found.")

db.close()

Opdater: FastAPI-slutpunkt

Handlingen Opdater (PUT eller PATCH) giver dig mulighed for at ændre et eksisterende element. Typisk finder du elementet ud fra dets ID, opdaterer dets attributter og gennemfører ændringerne.

# ... (FastAPI app, imports, get_db, models)

class TodoUpdate(BaseModel):
    title: str | None = None
    description: str | None = None
    completed: bool | None = None

@app.put("/todos/{todo_id}", response_model=TodoResponse)
def update_todo(todo_id: int, todo_update: TodoUpdate, db: Session = Depends(get_db)):
    db_todo = db.query(Todo).filter(Todo.id == todo_id).first()
    if db_todo is None:
        raise HTTPException(status_code=404, detail="Todo not found")
    
    # Update fields only if provided
    for key, value in todo_update.dict(exclude_unset=True).items():
        setattr(db_todo, key, value)
    
    db.add(db_todo) # Re-add to session for update tracking
    db.commit()
    db.refresh(db_todo)
    return db_todo

Brug af exclude_unset=True i Pydantic sikrer, at kun de angivne felter bliver opdateret.

Opdater: SQLAlchemy-demo

Her er et kørbart eksempel, der viser, hvordan du opdaterer titlen og færdiggørelsesstatussen for et todo-element ved hjælp af SQLAlchemy.

from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# Setup Database and Model
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class Todo(Base):
    __tablename__ = "todos"
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    description = Column(String, default="")
    completed = Column(Boolean, default=False)

Base.metadata.create_all(bind=engine)
db = SessionLocal()

# Create an initial Todo to update
initial_todo = Todo(title="Draft report", completed=False)
db.add(initial_todo)
db.commit()
db.refresh(initial_todo)
print(f"Created Todo: ID={initial_todo.id}, Title='{initial_todo.title}', Completed={initial_todo.completed}\n")

# Update Operation (U)
print(f"--- Updating Todo ID {initial_todo.id} ---")
todo_to_update = db.query(Todo).filter(Todo.id == initial_todo.id).first()

if todo_to_update:
    todo_to_update.title = "Finalize report"
    todo_to_update.completed = True
    db.commit()
    db.refresh(todo_to_update)
    print(f"Updated Todo: ID={todo_to_update.id}, Title='{todo_to_update.title}', Completed={todo_to_update.completed}")
else:
    print(f"Todo with ID {initial_todo.id} not found.")

db.close()

Slet: FastAPI-slutpunkt

Handlingen Slet fjerner et element fra databasen. Det gøres normalt med en DELETE-forespørgsel, der målrettes et element ud fra dets ID.

# ... (FastAPI app, imports, get_db, models)

@app.delete("/todos/{todo_id}", status_code=204) # 204 No Content for successful deletion
def delete_todo(todo_id: int, db: Session = Depends(get_db)):
    db_todo = db.query(Todo).filter(Todo.id == todo_id).first()
    if db_todo is None:
        raise HTTPException(status_code=404, detail="Todo not found")
    
    db.delete(db_todo)
    db.commit()
    return {"message": "Todo deleted successfully"} # FastAPI automatically handles 204

En vellykket sletning returnerer ofte statuskoden 204 No Content, hvilket betyder, at forespørgslen blev gennemført, men at der ikke er noget indhold at sende tilbage.

Slet: SQLAlchemy-demo

Lad os køre et script, der demonstrerer, hvordan du sletter et todo-element. Først opretter du et, derefter sletter du det og forsøger at læse det igen for at bekræfte, at det er fjernet.

from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# Setup Database and Model
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class Todo(Base):
    __tablename__ = "todos"
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    description = Column(String, default="")
    completed = Column(Boolean, default=False)

Base.metadata.create_all(bind=engine)
db = SessionLocal()

# Create an initial Todo to delete
todo_to_delete = Todo(title="Clean garage")
db.add(todo_to_delete)
db.commit()
db.refresh(todo_to_delete)
print(f"Created Todo: ID={todo_to_delete.id}, Title='{todo_to_delete.title}'\n")

# Delete Operation (D)
print(f"--- Deleting Todo ID {todo_to_delete.id} ---")
db.delete(todo_to_delete)
db.commit()
print(f"Todo ID {todo_to_delete.id} deleted.\n")

# Verify deletion by trying to read it
print("--- Verifying deletion ---")
verify_deleted = db.query(Todo).filter(Todo.id == todo_to_delete.id).first()
if verify_deleted is None:
    print(f"Successfully verified: Todo ID {todo_to_delete.id} is no longer in the database.")
else:
    print(f"Error: Todo ID {todo_to_delete.id} still found.")

db.close()

CRUD-udfordring

Du har lært de grundlæggende CRUD-handlinger! Nu kan du teste din forståelse af, hvordan SQLAlchemys metoder svarer til disse handlinger.

Opsummering og næste trin

Godt klaret! I denne lektion har du lært at implementere de grundlæggende CRUD-handlinger i FastAPI ved hjælp af SQLAlchemy:

  • Opret (POST): Brug af db.add(), db.commit() og db.refresh().
  • Læs (GET): Brug af db.query().all() til lister og db.query().filter().first() til enkelte elementer.
  • Opdatér (PUT): Hentning af et element, ændring af dets attributter og derefter db.commit() og db.refresh().
  • Slet (DELETE): Hentning af et element og derefter db.delete() og db.commit().

Disse færdigheder er afgørende for at bygge enhver datadrevet API. På det næste kursus går vi i dybden med avancerede emner som brugerautentificering og -autorisation for at sikre dine API-slutpunkter!

Gratis at komme i gang

Lær Bootcamp i FastAPI-backendudvikling med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
21
Lektioner
84

Ofte stillede spørgsmål

Er lektionen “CRUD-operationer med SQLAlchemy” gratis?

Ja — alle 3 lektioner i læringssporet Bootcamp i FastAPI-backendudvikling, inklusive “CRUD-operationer med SQLAlchemy”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Bootcamp i FastAPI-backendudvikling-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “CRUD-operationer med SQLAlchemy”?

Implementér Create-, Read-, Update- og Delete-operationer til Deres API-endpoints ved hjælp af SQLAlchemy ORM. Du øver dig i Bootcamp i FastAPI-backendudvikling med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Bootcamp i FastAPI-backendudvikling?

Der kræves ingen tidligere erfaring. Bootcamp i FastAPI-backendudvikling på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “CRUD-operationer med SQLAlchemy”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Bootcamp i FastAPI-backendudvikling-lektion?

Ja. Alle Bootcamp i FastAPI-backendudvikling-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Grundlæggende SQLAlchemy ORM
  2. Forbind FastAPI til PostgreSQL
  3. CRUD-operationer med SQLAlchemy
  4. Databasemigrationer med Alembic
← Tilbage til Bootcamp i FastAPI-backendudvikling