К основному содержанию
правило

peewee — правило для Cursor: что делает и как установить

Задаёт стандарты работы с ORM Peewee в Python: настройку BaseModel, внешние ключи с backref, транзакции atomic и защиту от проблемы N+1.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/peewee.mdc
Открыть на GitHub

Что делает peewee

Правило инструктирует ИИ писать чистый код для Peewee ORM в файлах **/*.py. Оно требует выносить подключение к базе данных в единый BaseModel, называть модели в единственном числе и передавать вызываемый объект datetime.datetime.now без скобок в значения по умолчанию. Для связей между таблицами правило обязывает указывать параметры backref и on_delete.

Для надёжности данных многошаговые операции оборачиваются в контекстный менеджер db.atomic(). Подключение и вызов create_tables выносятся строго в этап инициализации приложения, чтобы избежать повторных коннектов. Запросы к связанным таблицам агент оптимизирует через join() или prefetch(), отсекая проблему N+1.

Правило рассчитано только на Peewee. Если в проекте уже используется SQLAlchemy или Django ORM, эта инструкция будет сбивать генерацию моделей.

Какие задачи решает

  • связать модели Peewee через единый BaseModel
  • настроить внешние ключи с каскадным удалением через backref и on_delete
  • устранить проблему N+1 в запросах с помощью join() и prefetch()
  • упаковать цепочку операций с базой в транзакцию db.atomic()

Примеры запросов агенту

  • Создай модели User и Post с каскадным удалением записей
  • Оптимизируй выборку постов с авторами, чтобы избежать N+1
  • Напиши функцию создания пользователя и его первого поста внутри транзакции

Как установить peewee

Вручную: положить файлы

.cursor/rules/peewee.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о peewee

Как установить peewee в Cursor?

Сохраните файл правила по пути .cursor/rules/peewee.mdc в корне вашего проекта. Cursor автоматически применит его ко всем файлам по маске **/*.py.

Что делает правило peewee?

Оно направляет редактор при генерации кода для Peewee ORM, требуя правильной структуры BaseModel, единственного числа в именах моделей, безопасных внешних ключей и атомарных транзакций.

Как правило решает проблему N+1 запросов?

Инструкция предписывает объединять связанные выборки через методы join() или prefetch(). Это загружает связанные данные за один запрос к базе данных.

Исходный текст

peewee.mdc · CC0-1.0
---
description: Definitive guidelines for writing robust, maintainable, and performant Peewee ORM code in Python, covering data modeling, querying, and application structure.
globs: **/*.py
---
# peewee Best Practices

Peewee is a lightweight, expressive ORM for Python. These guidelines ensure your Peewee code is clean, efficient, and aligns with modern best practices as of 2025.

---

## 1. Code Organization and Structure

Always establish a clear, DRY (Don't Repeat Yourself) structure for your Peewee models and database connection.

### 1.1 Define a `BaseModel` for Database Connection

Centralize your database instance within a `BaseModel` to avoid repetitive declarations and ensure all models use the same connection.

❌ BAD: Direct database assignment in every model
```python
from peewee import *

db = SqliteDatabase('app.db')

class User(Model):
    username = CharField()
    class Meta:
        database = db # Repeated for every model
```

✅ GOOD: Inherit from a `BaseModel`
```python
from peewee import *

db = SqliteDatabase('app.db')

class BaseModel(Model):
    class Meta:
        database = db

class User(BaseModel):
    username = CharField(unique=True)
```

### 1.2 Model Naming Convention

Name your model classes in the singular form. Peewee automatically pluralizes table names (e.g., `User` -> `user`).

❌ BAD: Plural model name
```python
class Users(BaseModel): # Table might be 'userss' or 'users' depending on backend
    name = CharField()
```

✅ GOOD: Singular model name
```python
class User(BaseModel): # Table will be 'user'
    name = CharField()
```

### 1.3 Explicit Imports for Model Definitions

For model definition files, use `from peewee import *` for convenience. This is a common and accepted pattern within the Peewee ecosystem. For other modules or specific utility functions, prefer explicit imports.

❌ BAD: Overly verbose imports for model definitions
```python
from peewee import Model, CharField, IntegerField, SqliteDatabase, DateTimeField # ... and so on
```

✅ GOOD: Concise model definition imports
```python
from peewee import * # For model definition files (e.g., models.py)
import datetime

# In other files (e.g., main.py, services.py), for specific functions/classes:
from peewee import SqliteDatabase, DoesNotExist
```

## 2. Data Modeling

Define robust models with clear field types, constraints, and relationships.

### 2.1 Explicit Field Constraints and Defaults

Always define fields with appropriate Python types, `unique=True` where necessary, and sensible `default` values. Peewee uses `id` as an auto-incrementing primary key by default if none is specified.

```python
import datetime
from peewee import *

db = SqliteDatabase('app.db')

class BaseModel(Model):
    class Meta:
        database = db

class User(BaseModel):
    username = CharField(unique=True, index=True) # Ensure uniqueness and fast lookups
    email = CharField(unique=True, null=False)
    created_at = DateTimeField(default=datetime.datetime.now) # Use datetime.datetime.now, not datetime.now()
    is_active = BooleanField(default=True)

class Post(BaseModel):
    user = ForeignKeyField(User, backref='posts', on_delete='CASCADE') # Define relationship and cascade delete
    title = CharField(max_length=255, null=False)
    content = TextField(null=False)
    published_at = DateTimeField(null=True) # Can be null until published
    views = IntegerField(default=0)
```

### 2.2 Foreign Key Relationships with `backref` and `on_delete`

Always define `ForeignKeyField` with a `backref` to easily access related objects from the parent model. Specify `on_delete` for database-level referential integrity.

❌ BAD: Missing `backref` and `on_delete`
```python
class Comment(BaseModel):
    post = ForeignKeyField(Post) # Cannot easily get comments from a Post instance
    text = TextField()
```

✅ GOOD: With `backref` and `on_delete`
```python
class Comment(BaseModel):
    post = ForeignKeyField(Post, backref='comments', on_delete='CASCADE') # `post.comments` will work
    author = ForeignKeyField(User, backref='comments', on_delete='SET NULL', null=True) # Example with SET NULL
    text = TextField()
```

## 3. Database Connection and Transactions

Manage your database connections and ensure data integrity with transactions.

### 3.1 Connect and Create Tables Once at Application Startup

Establish the database connection and create tables only once when your application initializes. Close the connection if not using persistent connections or a framework that manages it.

❌ BAD: Connecting/creating tables in every script or function
```python
# In script A
db.connect()
db.create_tables([User, Post])

# In script B
db.connect() # Redundant, potential for errors
```

✅ GOOD: Centralized application startup
```python
# app_init.py (or main entry point)
from peewee import *
import datetime

db = SqliteDatabase('app.db')

class BaseModel(Model):
    class Meta:
        database = db

class User(BaseModel):
    username = CharField(unique=True)

class Post(BaseModel):
    user = ForeignKeyField(User, backref='posts')
    title = CharField()

def initialize_db():
    db.connect()
    db.create_tables([User, Post]) # Pass all models here
    db.close() # Close immediately if not using persistent connections

if __name__ == '__main__':
    initialize_db()
    print("Database initialized.")
    # Now, in your application logic, you'd open/close connections per request/operation
    # or use a connection pool.
```

### 3.2 Use Transactions for Atomic Operations

Wrap any multi-step database modifications in a transaction (`with db.atomic():`) to guarantee atomicity and improve performance.

❌ BAD: Multiple, non-atomic operations
```python
user = User.create(username='alice')
Post.create(user=user, title='First post') # If this fails, user is still created, leading to inconsistency
```

✅ GOOD: Atomic transaction
```python
try:
    with db.atomic():
        user = User.create(username='bob')
        Post.create(user=user, title='Second post') # Both succeed or both fail
except IntegrityError:
    print("Failed to create user and post due to integrity error.")
```

## 4. Query Optimization

Write efficient queries to minimize database load and improve response times.

### 4.1 Avoid N+1 Query Problem

Use `join()` or `prefetch()` to load related objects in a single query, preventing the N+1 problem.

❌ BAD: N+1 queries
```python
# Fetching posts, then iterating to get each user's username
for post in Post.select():
    print(f"{post.title} by {post.user.username}") # Each post.user.username triggers a new query
```

✅ GOOD: Single query with `join()`
```python
for post in Post.select().join(User):
    print(f"{post.title} by {post.user.username}") # User data loaded with post
```

### 4.2 Use Bulk Operations for Inserts

For inserting many records, use `bulk_create()` for significant performance gains by reducing the number of database round trips.

❌ BAD: Individual `create()` calls in a loop
```python
users_data = [{'username': f'user_{i}'} for i in range(100)]
for data in users_data:
    User.create(**data) # 100 separate INSERT statements
```

✅ GOOD: Single `bulk_create()` call
```python
users_data = [{'username': f'user_{i}'} for i in range(100)]
User.bulk_create([User(**data) for data in users_data]) # Single INSERT statement (or few, depending on batch size)
```

### 4.3 Atomic Updates

Perform updates atomically using `Model.update().where().execute()` to prevent race conditions and improve efficiency.

❌ BAD: Fetch-modify-save (prone to race conditions)
```python
post = Post.get(Post.id == 1)
post.views += 1
post.save() # Another process could have incremented views between get and save
```

✅ GOOD: Atomic update
```python
Post.update(views=Post.views + 1).where(Post.id == 1).execute() # Single, atomic operation
```

### 4.4 Pagination

Use the built-in `paginate()` method for efficient result set slicing, especially for large datasets.

```python
# Get page 2, with 20 items per page, ordered by username
users_page_2 = User.select().order_by(User.username).paginate(2, 20)
```

## 5. Security Best Practices

Peewee handles SQL injection prevention by default through parameterized queries. Focus on proper input validation in your application logic.

### 5.1 Trust Peewee's Query Builder

Avoid constructing SQL strings manually. Always use Peewee's ORM methods and expressions, which automatically parameterize inputs.

❌ BAD: Manual string formatting (vulnerable to injection)
```python
# DO NOT DO THIS. This is a severe security vulnerability.
user_input = "'; DROP TABLE users; --"
query = f"SELECT * FROM user WHERE username = '{user_input

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Все правила IDE по теме «Бэкенд и API» →
prisma-expert sickn33 Скилл помогает разбирать схемы Prisma, миграции и запросы. Пригодится, когда нужно найти причину ошибки или проверить изменения перед деплоем. CX Codex +1 4 200установок drizzle bobmatnyc Скилл передаёт агенту правила работы с Drizzle ORM в TypeScript. Он помогает писать схемы таблиц, связывать сущности и собирать SQL-запросы без лишней документации под рукой. CX Codex +1 1 800установок database-design davila7 Скилл задаёт правила проектирования баз данных для Claude Code. Он помогает выбрать подходящую СУБД, настроить индексы и избежать антипаттернов вроде слепого выбора PostgreSQL. 994установок dart-drift Stanislav [MADTeacher] Chernyshev Скилл для работы с Drift в Dart CLI, серверных и десктопных приложениях без Flutter: таблицы, запросы, миграции, PostgreSQL. CX Codex +1 466установок bun-drizzle-integration secondsky Скилл подсказывает агенту, как связать Drizzle ORM с драйвером bun:sqlite: схема, миграции, CRUD и транзакции в одном месте. CX Codex +1 420установок drizzle-orm-d1 secondsky Скилл для работы с Cloudflare D1 через Drizzle ORM: схемы, типизированные запросы, миграции Drizzle Kit и разбор типовых ошибок D1. CX Codex +1 416установок

Из того же набора240

Весь набор →
playwright Правило задаёт Cursor стандарты написания end-to-end тестов на Playwright: официальный раннер, устойчивые локаторы, отказ от ручных задержек. ★ 3 580звёзд репо pillow Задаёт правила работы с библиотекой Pillow в файлах Python. Требует закрывать файлы через контекстные менеджеры и безопасно сохранять форматы изображений. ★ 3 580звёзд репо php Правило задаёт стиль и практики безопасного PHP-кода: PSR-12, строгие типы, PHP 8.4+, проверки API и тестирование. ★ 3 580звёзд репо phoenix Правило для Cursor задаёт, как писать Phoenix-приложения на Elixir: контексты, форматирование, тесты. Пригодится, если агент уже правит ваш код. ★ 3 580звёзд репо pdoc Правило задаёт формат docstring и type hints в Python-коде, который документируется через pdoc. Пригодится, когда нужно привести описание публичного API к единому виду. ★ 3 580звёзд репо pandas Правило для Cursor задаёт стиль работы с pandas: векторизация вместо циклов, явные .loc и .iloc, экономные типы данных. Пригодится, если агент часто пишет медленный код. ★ 3 580звёзд репо opencv-python Набор инструкций для Cursor, нацеленный на быстрый код компьютерного зрения на Python. Правило запрещает циклы по пикселям и требует векторизации. ★ 3 580звёзд репо openai Правило помогает вести проект с OpenAI API: хранить промпты отдельно, правильно создавать клиент и задавать модели чёткие инструкции. Пригодится при разработке на Python. ★ 3 580звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой