Sqlalchemy
61.8 Async SQLAlchemy with asyncpg
Alright, let’s talk about making SQLAlchemy sing asynchronously. You’re here because you’ve felt the pain of your beautifully crafted FastAPI (or whatever async framework you’re using) grinding to a halt every time it has to go talk to the database, waiting patiently while your precious event loop blocks. It’s 2023, we don’t wait for anything anymore, not even our databases. So we reach for asyncpg and SQLAlchemy’s async support. This isn’t your grandfather’s ORM. It’s a different beast, and you have to treat it with respect, or it will bite you. The core idea is simple: instead of executing queries and blocking the thread until the database responds, we await the results, freeing the event loop to go handle other requests while the database does its thing.
61.7 Alembic: Database Migration Management
Alright, let’s talk about the part of the job we all secretly dread but can’t live without: changing the database schema after you’ve already got data in it. You can’t just DROP TABLE and start over like you did in the first week of the project. This is where Alembic comes in. Think of it as version control for your database schema, and it’s about as much fun as explaining version control to a manager, but infinitely more necessary.
61.6 Querying with SQLAlchemy ORM: filter, join, order_by, limit
Right, so you’ve got some data in there. Congratulations. Now let’s actually do something with it. The SQLAlchemy ORM is where this goes from being a neat trick to being your superpower. It lets you query your database using Python objects and methods, which is infinitely more pleasant than string-stitching raw SQL. But with great power comes the great responsibility of not writing horribly inefficient queries. Let’s get into it.
61.5 SQLAlchemy ORM: Declarative Models, Sessions, and Relationships
Alright, let’s get our hands dirty with the ORM. You’ve probably heard that an ORM (Object-Relational Mapper) is a way to talk to your database using the objects and paradigms of your chosen language—in our case, Python—instead of writing raw SQL. SQLAlchemy’s ORM is the gold standard for this in Python, and for good reason. It’s powerful, flexible, and doesn’t treat you like an idiot. It gives you escape hatches to raw SQL when you need them, which is the sign of a mature tool that respects your intelligence.
61.4 SQLAlchemy Core: Engine, Connection, Table, and Select
Alright, let’s roll up our sleeves and get to the good stuff. Forget the high-level ORM magic for a moment—we’re going to talk about the foundation it’s all built on: SQLAlchemy Core. This is where you get to talk to the database in its own language (SQL) but with all the power and safety of Python. It’s like having a brilliant translator who not only converts your words but also stops you from accidentally insulting the king. We’ll cover the absolute essentials: the Engine, the Connection, defining a Table, and crafting a Select statement.
61.3 sqlite3 Row Factories and Context Managers
Right, let’s get our hands dirty with the two things that will immediately make your sqlite3 code in Python less of a chore and more… well, Pythonic. We’re talking about row factories and context managers. These aren’t just fancy tricks; they’re fundamental upgrades to your workflow that save you from tedious, error-prone boilerplate. The Default Row Object is a Crime Against Convenience Out of the box, when you fetch rows with sqlite3, you get a sqlite3.Cursor object that returns rows as tuples. This is fine if you enjoy remembering that row[3] is the user’s birthday and not, say, their shoe size. It’s brittle, unreadable, and a surefire way to introduce bugs the second you change your SELECT statement.
61.2 Parameterized Queries and Preventing SQL Injection
Right, let’s talk about the one security mistake that will get your app featured on the evening news for all the wrong reasons: SQL injection. It’s the digital equivalent of leaving your front door wide open with a sign that says “All my valuables are in the living room, please don’t steal them.” It’s absurdly common, devastatingly effective, and, frankly, embarrassingly easy to prevent. I’m going to show you how. Not because some security manual told me to, but because I’ve seen the cleanup, and it’s not pretty.
61.1 sqlite3: Connecting, Executing Queries, and Fetching Results
Alright, let’s get our hands dirty with sqlite3. Forget the enterprise-grade, multi-terabyte, distributed-systems horror for a moment. Most applications, especially when you’re starting out, don’t need that firepower. They need a reliable, simple, and shockingly capable data store. That’s sqlite. It’s not some toy; it’s a full-featured, SQL-enabled database engine that lives in a single file. It’s the pocket knife of databases, and it’s probably already on your system. The beauty, and sometimes the curse, of the sqlite3 module in Python’s standard library is its simplicity. It’s a very thin wrapper around the SQLite C library. This means it’s powerful and fast, but it also means it expects you to know what you’re doing. It won’t hold your hand. I like that. You should too.