vault backup: 2026-05-30 16:02:33

This commit is contained in:
Rainyy21
2026-05-30 16:02:33 -04:00
commit 96449f8968
43 changed files with 2837 additions and 0 deletions
@@ -0,0 +1,176 @@
# SQLAlchemy 2.0 Tutorial (Recipe Scraper Edition)
This guide covers SQLAlchemy 2.0, the industry-standard SQL toolkit and Object-Relational Mapper (ORM) for Python. We'll use the **Recipe Web Scraper** project models as our primary examples.
---
## 1. What is SQLAlchemy?
SQLAlchemy has two main components:
1. **Core**: A SQL abstraction layer (SQL Expression Language, Schema definitions, Engine).
2. **ORM**: A layer on top of Core that maps Python classes to database tables.
In this project, we primarily use the **ORM** to treat recipes and ingredients as Python objects.
---
## 2. Defining Models (The Modern Way)
SQLAlchemy 2.0 introduced a type-hint-centric way to define models using `Mapped` and `mapped_column`.
### The Base Class
All models inherit from a common `Base` class created from `DeclarativeBase`.
```python
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
```
### Example: The Recipe Model
```python
from sqlalchemy import String, Integer, DateTime
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
class Recipe(Base):
__tablename__ = "recipes" # Name of the table in the DB
# Primary Key
id: Mapped[int] = mapped_column(primary_key=True)
# Simple Columns (SQLAlchemy infers types from Mapped[T])
url: Mapped[str] = mapped_column(String, unique=True, index=True)
title: Mapped[str]
total_time: Mapped[int | None] # Optional column (nullable=True)
# Column with a default value
scraped_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
# Relationships (Defined in section 4)
ingredients: Mapped[list["Ingredient"]] = relationship(back_populates="recipe")
```
---
## 3. Engine and Session
### The Engine
The **Engine** is the starting point for any SQLAlchemy application. It manages a pool of connections to the database.
```python
from sqlalchemy import create_engine
# SQLite: The '///' means relative path to the current directory
engine = create_engine("sqlite:///recipes.db", echo=True)
# echo=True logs all SQL commands to the terminal (great for debugging)
```
### Creating Tables
You can tell SQLAlchemy to create all tables defined in your models:
```python
Base.metadata.create_all(engine)
```
### The Session
The **Session** handles the conversation with the database. Use `sessionmaker` to create a factory for sessions.
```python
from sqlalchemy.orm import sessionmaker
SessionLocal = sessionmaker(bind=engine)
# Use as a context manager to ensure the connection is closed
with SessionLocal() as session:
# do work here
pass
```
---
## 4. Relationships (1-to-Many)
In our project, one `Recipe` has many `Ingredients`.
### Foreign Key
The "child" table (`Ingredient`) must have a column pointing to the "parent" table (`Recipe`).
```python
from sqlalchemy import ForeignKey
class Ingredient(Base):
__tablename__ = "ingredients"
id: Mapped[int] = mapped_column(primary_key=True)
# Links to 'recipes.id'
recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id"))
text: Mapped[str]
# Back-reference to the parent Recipe object
recipe: Mapped["Recipe"] = relationship(back_populates="ingredients")
```
### Cascades
`cascade="all, delete-orphan"` ensures that if you delete a Recipe, all its Ingredients are also deleted automatically.
---
## 5. CRUD Operations
### Create (Insert)
```python
with SessionLocal() as session:
new_recipe = Recipe(title="Pasta Carbonara", url="https://example.com/pasta")
session.add(new_recipe)
session.commit() # Save to DB
```
### Read (Select)
```python
from sqlalchemy import select
with SessionLocal() as session:
# 1. Get by ID
recipe = session.get(Recipe, 1)
# 2. Filter by column
stmt = select(Recipe).where(Recipe.title == "Pasta Carbonara")
result = session.execute(stmt).scalars().first()
# 3. Get all
all_recipes = session.query(Recipe).all() # Older syntax, still common
```
### Update
```python
with SessionLocal() as session:
recipe = session.get(Recipe, 1)
recipe.title = "Authentic Pasta Carbonara"
session.commit()
```
### Delete
```python
with SessionLocal() as session:
recipe = session.get(Recipe, 1)
session.delete(recipe)
session.commit()
```
---
## 6. Common Pitfalls
1. **Lazy Loading**: By default, SQLAlchemy doesn't load relationships until you access them. This can cause "N+1" performance issues. Use `joinedload` to fetch everything in one query.
2. **Session Lifecycle**: Always use a context manager (`with session:`) or close your sessions manually.
3. **Commit vs Flush**: `session.flush()` sends changes to the DB but doesn't permanentize them. `session.commit()` makes them permanent.
---
## 7. Next Steps: Migrations with Alembic
As your models change (e.g., you add a `rating` column), you shouldn't just delete the DB and start over. **Alembic** is the tool used to handle database migrations.
Install it with: `pip install alembic`
+93
View File
@@ -0,0 +1,93 @@
---
title: Poetry Setup and Project Initialization Guide
created: 2026-05-22
tags:
- python
- python_tool
- poetry
- guide
category: python_tool
status: reference
up: "[[project/index]]"
related:
- "[[poetry_project_ideas]]"
- "[[__init__.py explained]]"
source:
author:
published:
---
# Poetry Setup and Project Initialization Guide
This guide explains how to install Poetry and start a new Python project, based on the concepts from "Introduction to Poetry - Python Dependency Management".
## 1. How to Install Poetry
While the introductory notes focus on usage, the standard way to install Poetry is via the official installer script.
### macOS / Linux / WSL
Open your terminal and run:
```bash
curl -sSL https://install.python-poetry.org | python3 -
```
### Windows (PowerShell)
Open PowerShell and run:
```powershell
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
```
### Verification
After installation, restart your terminal and verify by running:
```bash
poetry --version
```
---
## 2. How to Start a Project
There are two main ways to start a project with Poetry:
### Method A: Creating a New Project (Recommended for new folders)
To create a new project with a predefined folder structure:
```bash
poetry new my-project
```
This creates a directory named `my-project` with the following structure:
```text
my-project/
├── pyproject.toml
├── README.md
├── my_project/
│ └── __init__.py
└── tests/
└── __init__.py
```
### Method B: Initializing an Existing Project
If you already have a project folder and want to add Poetry to it:
1. Navigate to your project directory:
```bash
cd my-existing-project
```
2. Run the interactive initialization command mentioned in the introduction:
```bash
poetry init
```
This will walk you through creating your `pyproject.toml` file interactively.
---
## 3. Key Concepts from the Introduction
- **`pyproject.toml`**: The single source of truth for your project configuration (replaces `requirements.txt`, `setup.py`, etc.).
- **Deterministic Resolution**: Poetry ensures your dependencies are resolved correctly using a lockfile (`poetry.lock`).
- **Isolation**: Poetry automatically manages virtual environments for you, ensuring your global Python installation stays clean.
## 4. Basic Workflow Commands
Once your project is started, use these commands to manage it:
- `poetry add <package>`: Add and install a new dependency.
- `poetry install`: Install all dependencies defined in `pyproject.toml`.
- `poetry shell`: Activate the project's virtual environment.
- `poetry run <command>`: Run a command inside the virtual environment without activating it.