Skip to content

Commit e00e9f6

Browse files
authored
Merge pull request #95 from sqlitecloud/feat/fastapi-sqlalchemy-quickstart
Revised SQLAlchemy Quickstart guide
2 parents 2458ceb + bc8c01e commit e00e9f6

1 file changed

Lines changed: 12 additions & 46 deletions

File tree

sqlite-cloud/quick-start-fastapi-sqlalchemy.mdx

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ status: publish
66
slug: quick-start-sqlalchemy-orm
77
---
88

9-
In this quickstart, we will show you how to get started with SQLite Cloud and SQLAlchemy by building a FastAPI backend that connects to and reads from a SQLite Cloud database.
9+
In this quickstart, we will show you how to get started with SQLite Cloud by building a FastAPI backend that connects to and reads from a SQLite Cloud database using SQLAlchemy.
1010

1111
---
1212

@@ -37,20 +37,10 @@ pip install "fastapi[standard]" sqlalchemy sqlalchemy-sqlitecloud
3737

3838
- Do NOT remove the quotes around the FastAPI package.
3939
- `sqlalchemy-sqlitecloud` includes `sqlitecloud`, so no need to install the latter separately.
40-
- Update `.venv/lib/python{version}/site-packages/sqlitecloud/__init__.py`:
41-
42-
```py
43-
from .dbapi2 import *
44-
45-
# from .dbapi2 import (
46-
# PARSE_COLNAMES,
47-
# ...
48-
# )
49-
```
5040

5141
4. **App setup**
52-
- From your current directory, create a sub-directory `fastapi_sqlc_app` with an empty `__init__.py` file to indicate the new sub-dir is a package.
53-
- NOTE: Create the remaining project files in this sub-dir as well.
42+
- From your current directory, create a sub-directory `fastapi_sqlc_app` with an empty `__init__.py` file to indicate the new sub-directory is a package.
43+
- NOTE: We will create all remaining project files in this sub-directory.
5444

5545
```bash
5646
mkdir fastapi_sqlc_app
@@ -75,61 +65,36 @@ Base = declarative_base()
7565

7666
- Create a new file `models.py` and copy in the following code defining 2 SQLAlchemy ORM "models", or classes, to interact with the DB.
7767
- `__tablename__` is the name of a model's corresponding DB table.
78-
- Most class attributes/ table `Column`s below are passed a class type as the first argument. NOTE: The `Album` class' `id` attribute passes `AlbumId` as the first arg.
79-
- We use the `relationship` function to create an explicit, bidirectional link between the 2 models. Let's say:
80-
- We have an instance of the `Artist` class called `taylor_swift`. Accessing the attribute `taylor_swift.albums` would return:
81-
- a list of `Album` SQLAlchemy models from the `albums` DB table, whose foreign key `ArtistId` points to the `taylor_swift` record in the `artists` table.
82-
- Or simply put, a list of Taylor Swift's albums.
83-
- We have an instance of the `Album` class called `fearless`. Accessing the attribute `fearless.artist` would return:
84-
- an `Artist` SQLAlchemy model from the `artists` DB table, again using the foreign key `ArtistId` to get the right record.
85-
- Or simply put, the creator of the album Fearless (also Taylor Swift).
68+
- The `Album` class' `id` attribute maps to the `AlbumId` column in the `albums` table. All other class attribute names match their corresponding table column names.
8669

8770
```py
8871
from .database import Base
8972

9073
from sqlalchemy import Column, ForeignKey, Integer, String
91-
from sqlalchemy.orm import relationship
9274

9375
class Artist(Base):
9476
__tablename__ = "artists"
9577

9678
ArtistId = Column(Integer, primary_key=True)
9779
Name = Column(String)
9880

99-
albums = relationship("Album", back_populates="artist")
100-
10181
class Album(Base):
10282
__tablename__ = "albums"
10383

10484
id = Column("AlbumId", Integer, primary_key=True)
10585
Title = Column(String)
10686
ArtistId = Column(Integer, ForeignKey('artists.ArtistId'))
107-
108-
artist = relationship("Artist", back_populates="albums")
10987
```
11088

111-
- Create a new file `schemas.py` and copy in the following code defining 2 Pydantic models, or "schemas", to validate the shapes of the response data.
112-
- NOTE: The `Album` Pydantic model checks for `ArtistName` rather than `ArtistId` defined in the `Album` SQLAlchemy model in `models.py`.
113-
- By default, SQLAlchemy "lazy loads", i.e. it only gets relationship data from the DB when we access the model's attribute containing that data.`orm_mode = True` enables the Pydantic model to read a returned ORM (in this case, SQLAlchemy) model and include relationship data.
89+
- Create a new file `schemas.py` and copy in the following code defining a Pydantic model, or "schema", to validate the shape of the response data.
11490

11591
```py
11692
from pydantic import BaseModel
11793

118-
class Album(BaseModel):
94+
class AlbumResponse(BaseModel):
11995
id: int
12096
Title: str
12197
ArtistName: str
122-
123-
class Config:
124-
orm_mode = True
125-
126-
class Artist(BaseModel):
127-
ArtistId: int
128-
Name: str
129-
albums: list[Album] = []
130-
131-
class Config:
132-
orm_mode = True
13398
```
13499

135100
- Create a new file `read.py` and copy in the following code creating a reusable utility function to read album data.
@@ -145,7 +110,9 @@ def get_albums(db: Session, skip: int = 0, num: int = 20):
145110

146111
- Create a new file `main.py` and copy in the following code.
147112
- The `get_db` function handles creating and closing a new `SessionLocal` instance, or DB connection/ session, for every request.
148-
- NOTE: The function below returns a list of SQLAlchemy `Album` models. However, only the data declared in the Pydantic schemas will be returned to the client.
113+
- A GET request to the `/albums/` endpoint calls the `read_albums` function, which returns a list of SQLAlchemy `Album` models. The `response_model` ensures only data declared in the Pydantic schema is returned to the client.
114+
- The `AlbumResponse` Pydantic model in `schemas.py` has `ArtistName`, as opposed to `ArtistId` defined in the `Album` SQLAlchemy model in `models.py`.
115+
- `read_albums` calls the `get_albums` function in `read.py`. `get_albums` queries the `Album` ORM model/ `albums` DB table for the first 20 albums, and joins the `Artist` ORM model/ `artists` DB table to retrieve the `Artist.Name` (re-labeled `ArtistName`) expected by the `AlbumResponse` Pydantic model.
149116

150117
```py
151118
from .database import SessionLocal
@@ -163,7 +130,7 @@ def get_db():
163130
finally:
164131
db.close()
165132

166-
@app.get("/albums/", response_model=list[schemas.Album])
133+
@app.get("/albums/", response_model=list[schemas.AlbumResponse])
167134
def read_albums(skip: int = 0, num: int = 20, db: Session = Depends(get_db)):
168135
albums = read.get_albums(db, skip=skip, num=num)
169136
return albums
@@ -188,8 +155,7 @@ AttributeError: module 'sqlitecloud.dbapi2' has no attribute 'sqlite_version_inf
188155

189156
7. **References**
190157

191-
If you're new to FastAPI and/or want to learn more about how to work with ORMs in FastAPI, we referenced FastAPI's [SQL Databases Tutorial](https://fastapi.tiangolo.com/tutorial/sql-databases/) extensively when writing this Quickstart.
192-
193-
If you're new to SQLAlchemy, refer to [their latest docs](https://docs.sqlalchemy.org/en/20/).
158+
- If you're new to FastAPI and/or want to learn more about how to work with ORMs in FastAPI, we referenced FastAPI's [introductory example](https://fastapi.tiangolo.com/#example) and [SQL Databases tutorial](https://fastapi.tiangolo.com/tutorial/sql-databases/) extensively when writing this Quickstart.
159+
- If you're new to SQLAlchemy, refer to [their latest docs](https://docs.sqlalchemy.org/en/20/).
194160
195161
And that's it! You've successfully built a FastAPI app that uses SQLAlchemy ORM to read data from a SQLite Cloud database.

0 commit comments

Comments
 (0)