SQLAlchemy + CUBRID quickstart¶
One Python script that writes, reads, updates and deletes rows in CUBRID with SQLAlchemy, first with SQLAlchemy Core (SQL expressions), then with the ORM (Python classes mapped to tables). You start a disposable local database in Docker, run the script, and clean up. Everything you need is on this page.
Plan on about 5 minutes once Docker and Python are installed and the database image is downloaded; the first download takes longer on a slow connection. New to CUBRID itself? Do your first CUBRID database from Python first: it explains the database, the connector and transactions.
Korean: SQLAlchemy 빠른 시작
What you need¶
- Linux or macOS with
bashorzsh. On Windows, use a WSL 2 terminal. - Docker with Compose v2:
docker compose versionmust print a version. - Python 3.11 or later on your machine:
python3 --version. The script runs on your machine; only the database runs in Docker. git.
The CUBRID image is published for x86_64 (linux/amd64); on an Apple Silicon
Mac, Docker runs it under emulation. This page was checked on Linux x86_64.
1. Get the code and a Python environment¶
Run these from the folder where you keep projects:
git clone https://github.com/cubrid-lab/cubrid-cookbook-python.git
cd cubrid-cookbook-python
cd quickstart/5min-sqlalchemy
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
Every later command on this page runs from this quickstart/5min-sqlalchemy
folder, with the venv active. The venv keeps the packages (sqlalchemy,
sqlalchemy-cubrid and the pycubrid driver) inside this folder. If you open a
new terminal, run cd back into the folder and source .venv/bin/activate
again.
2. Start the database¶
This starts one container from docker-compose.yml, which creates the database
testdb, and waits until its health check (a SELECT 1 inside the container)
passes.
Checkpoint. docker compose up returns without an error, and
docker compose ps lists the database as healthy:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
5min-sqlalchemy-cubrid-1 cubrid/cubrid:11.2 "/entrypoint.sh" cubrid 17 seconds ago Up 16 seconds (healthy) 127.0.0.1:33000->33000/tcp
The times differ on your machine. The script runs on your machine, so it
connects to localhost:33000, the port Docker publishes for the database
(PORTS column).
3. Run the script¶
Checkpoint. Expected output:
=== SQLAlchemy Core CRUD ===
Core query result: [(1, 'core-sample', 'v1')]
=== SQLAlchemy ORM CRUD ===
ORM query result: 1 orm-sample
Done. Core and ORM CRUD completed successfully.
What happened, in app.py:
- It connects with the URL
cubrid+pycubrid://dba@localhost:33000/testdb: thecubridSQLAlchemy dialect with thepycubriddriver, as userdbawith an empty password, to the databasetestdbonlocalhost:33000. - It creates two tables of its own,
cookbook_core_itemsandcookbook_orm_items. The Core part inserts the rowcore-sampleand reads it back as the tuple(item_id, item_name, val), then updates and deletes it. The ORM part does the same with aCookbookOrmItemobject and prints itsitem_idanditem_name. - On exit, even after an error, it drops both tables again.
Because the script creates both tables new each time, the ids are 1 on
every run, and you can run python app.py again at once with the same output.
It drops any existing tables with these two names, so run it only against a
database where those names are not used for anything else, such as this one.
4. Stop, run again and clean up¶
The script leaves no tables behind. To stop the database, choose how much to delete:
| Command | The container | Data |
|---|---|---|
docker compose stop |
stopped; docker compose start resumes it |
kept |
docker compose down |
removed | kept in this quickstart's Docker volumes; the next docker compose up -d --wait brings it back |
docker compose down -v |
removed | deleted, including the testdb database |
To run it again later, start the database with docker compose up -d --wait,
then run python app.py.
These commands act only on this folder's Compose project, named
5min-sqlalchemy after the folder: its container, its network and, with
-v, its two volumes (5min-sqlalchemy_cubrid_data,
5min-sqlalchemy_cubrid_databases). They never touch other containers. Run
deactivate to leave the venv, and rm -rf .venv to delete it.
Port 33000 is shared. This quickstart, the
FastAPI quickstart and the repository's root lab
(the cubrid service of the root docker-compose.yml) all publish their database on
127.0.0.1:33000. Each is a separate Compose project with its own data, so
only one can run at a time. Before you switch, run docker compose stop in the
folder of the one you are leaving.
If something goes wrong¶
docker: command not found, ordocker compose versionfails: install Docker with Compose v2 (Get Docker), and make sure the Docker daemon is running.Bind for 127.0.0.1:33000 failed: port is already allocated: something else holds port 33000. Find it withdocker ps --filter publish=33000. If it is one of this repository's labs, stop it from its own folder withdocker compose stop; otherwise stop the program you started yourself. Do not remove containers or volumes you did not create. A failed start leaves this project's container behind; rundocker compose downhere before you try again.- The database does not become healthy (
docker compose up --waitreportsunhealthy, or waits a long time): the first start createstestdband can take a minute. Checkdocker compose logs cubridfor the reason. ModuleNotFoundError: No module named 'sqlalchemy', orCan't load plugin: sqlalchemy.dialects:cubrid.pycubrid: the venv is not active. Runsource .venv/bin/activate, thenpython -m pip install -r requirements.txtagain.Database operation failed: (pycubrid.exceptions.OperationalError) failed to connect to CUBRID broker, followed by twoCleanup failed:lines: no database answers onlocalhost:33000. Start it withdocker compose up -d --wait.- A database or login error: the script connects to
testdbasdbawith an empty password, the settings this Compose file creates. Another CUBRID server on port 33000 has different ones; stop it as described above. -353 Failed to connect to database serverafter you update from an earlier Compose file: that file registered the database for the hostcubrid-sqlalchemy, and the database in your volumes still names it. The data is kept; point it atlocalhostand restart. Do not rundocker compose down -v, which deletes it.
docker compose up -d cubrid
docker compose exec -T -u cubrid cubrid sh -c 'sed -i -E "s/^(testdb[[:space:]]+[^[:space:]]+[[:space:]]+)[^[:space:]]+/\1localhost/" "$CUBRID_DATABASES/databases.txt"'
docker compose restart cubrid
docker compose up -d --wait
More fixes: the CUBRID quirks and pitfalls and the known issues.
Local only. The lab's
dbaaccount has no password, so the database listens on127.0.0.1only. Never use these settings for a shared or remote server.
What next?¶
- More SQLAlchemy with CUBRID (relationships, bulk inserts, upserts, reflection, collection types): the SQLAlchemy recipes.
- A production-shaped batch job with pandas and SQLAlchemy: the batch ETL template.
- A web API: the FastAPI quickstart.