← Назад к вопросам
Приведи пример использования ORM в Python
2.0 Middle🔥 131 комментариев
#Django#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Краткий ответ
ORM (Object-Relational Mapping) — инструмент для работы с БД через объекты вместо SQL. Основные ORM для Python: SQLAlchemy (универсальный), Django ORM (встроенный в Django), Tortoise ORM (асинхронный). Покажу примеры всех трёх с одинаковой моделью.
Что такое ORM?
ORM преобразует таблицы БД в классы Python:
Таблица users в БД:
+----+-------+--------------------+-----+
| id | name | email | age |
+----+-------+--------------------+-----+
| 1 | John | john@example.com | 30 |
| 2 | Jane | jane@example.com | 28 |
+----+-------+--------------------+-----+
Объект User в Python:
class User:
id = 1
name = 'John'
email = 'john@example.com'
age = 30
Пример 1: SQLAlchemy (самый популярный)
from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.orm import declarative_base, Session, relationship
from datetime import datetime
# Подключение к БД
engine = create_engine('postgresql://user:password@localhost/mydb')
Base = declarative_base()
# Определение модели
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=False)
email = Column(String(100), unique=True, nullable=False)
age = Column(Integer)
created_at = Column(DateTime, default=datetime.now)
# Связь с постами
posts = relationship('Post', back_populates='author')
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
title = Column(String(200), nullable=False)
content = Column(String(1000))
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
created_at = Column(DateTime, default=datetime.now)
# Связь с пользователем
author = relationship('User', back_populates='posts')
# Создание таблиц
Base.metadata.create_all(engine)
# Примеры операций
with Session(engine) as session:
# CREATE - создание
user = User(name='John', email='john@example.com', age=30)
session.add(user)
session.commit()
print(f'Created user with id: {user.id}')
# READ - чтение
user = session.query(User).filter(User.email == 'john@example.com').first()
print(f'Found user: {user.name}')
# UPDATE - обновление
user.age = 31
session.commit()
print(f'Updated user age to {user.age}')
# DELETE - удаление
session.delete(user)
session.commit()
print('Deleted user')
# СВЯЗЬ - работа с отношениями
user = User(name='Jane', email='jane@example.com')
post = Post(title='My First Post', content='Hello World', author=user)
session.add(user)
session.add(post)
session.commit()
# Чтение связанных данных
user = session.query(User).filter(User.email == 'jane@example.com').first()
print(f'User {user.name} has {len(user.posts)} posts')
for post in user.posts:
print(f' - {post.title}')
Пример 2: Django ORM
# models.py
from django.db import models
from django.utils import timezone
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
age = models.IntegerField(null=True, blank=True)
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
# views.py или shell
from django.core.management.base import BaseCommand
from .models import User, Post
# CREATE
user = User.objects.create(name='John', email='john@example.com', age=30)
print(f'Created user with id: {user.id}')
# READ
user = User.objects.get(email='john@example.com')
print(f'Found user: {user.name}')
# UPDATE
user.age = 31
user.save()
print(f'Updated user age to {user.age}')
# DELETE
user.delete()
print('Deleted user')
# СВЯЗЬ
user = User.objects.create(name='Jane', email='jane@example.com')
post = Post.objects.create(title='My Post', content='Content', author=user)
user = User.objects.get(email='jane@example.com')
for post in user.posts.all():
print(f'Post: {post.title}')
# ФИЛЬТРАЦИЯ
young_users = User.objects.filter(age__lt=30) # age < 30
for u in young_users:
print(u.name)
# СОРТИРОВКА
users = User.objects.all().order_by('-created_at') # DESC
# АГРЕГАЦИЯ
from django.db.models import Q, Count
users_with_posts = User.objects.annotate(
post_count=Count('posts')
).filter(post_count__gt=0)
Пример 3: Tortoise ORM (асинхронный)
from tortoise import Model, fields
from tortoise.contrib.pydantic import pydantic_model_creator
from tortoise import Tortoise
# Модели
class User(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=100)
email = fields.CharField(max_length=100, unique=True)
age = fields.IntField(null=True)
created_at = fields.DatetimeField(auto_now_add=True)
# Связь
posts: fields.ReverseRelation['Post']
class Meta:
table = 'users'
class Post(Model):
id = fields.IntField(pk=True)
title = fields.CharField(max_length=200)
content = fields.TextField()
author = fields.ForeignKeyField('models.User', related_name='posts')
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = 'posts'
# Асинхронные операции
import asyncio
async def main():
await Tortoise.init(
db_url='postgres://user:password@localhost/mydb',
modules={'models': ['__main__']}
)
await Tortoise.generate_schemas()
# CREATE
user = await User.create(name='John', email='john@example.com', age=30)
print(f'Created user with id: {user.id}')
# READ
user = await User.get(email='john@example.com')
print(f'Found user: {user.name}')
# UPDATE
user.age = 31
await user.save()
print(f'Updated user age to {user.age}')
# DELETE
await user.delete()
print('Deleted user')
# СВЯЗЬ
user = await User.create(name='Jane', email='jane@example.com')
post = await Post.create(
title='My Post',
content='Content',
author=user
)
# Чтение связанных
user_with_posts = await User.get(id=user.id).prefetch_related('posts')
print(f'User {user_with_posts.name} has {len(user_with_posts.posts)} posts')
# ЗАПРОСЫ
young_users = await User.filter(age__lt=30) # age < 30
all_users = await User.all().order_by('-created_at')
await Tortoise.close_connections()
if __name__ == '__main__':
asyncio.run(main())
Сравнение операций
CREATE (создание)
# SQLAlchemy
user = User(name='John', email='john@example.com')
session.add(user)
session.commit()
# Django ORM
user = User.objects.create(name='John', email='john@example.com')
# Tortoise ORM (async)
user = await User.create(name='John', email='john@example.com')
READ (чтение)
# SQLAlchemy
user = session.query(User).filter(User.email == 'john@example.com').first()
all_users = session.query(User).all()
# Django ORM
user = User.objects.get(email='john@example.com')
all_users = User.objects.all()
# Tortoise ORM (async)
user = await User.get(email='john@example.com')
all_users = await User.all()
UPDATE (обновление)
# SQLAlchemy
user.age = 31
session.commit()
# Django ORM
user.age = 31
user.save()
# Tortoise ORM (async)
user.age = 31
await user.save()
DELETE (удаление)
# SQLAlchemy
session.delete(user)
session.commit()
# Django ORM
user.delete()
# Tortoise ORM (async)
await user.delete()
Преимущества ORM
# ✅ Не нужно писать SQL вручную
user = User.objects.get(id=1)
# ✅ Защита от SQL injection
user = User.objects.filter(name=user_input) # Безопасно
# ✅ Переносимость между БД
# SQLAlchemy работает с PostgreSQL, MySQL, SQLite и т.д.
engine = create_engine('sqlite:///mydb.sqlite')
# Переключение: просто измени строку подключения
# ✅ Типизация и IDE поддержка
user = User.objects.get(id=1)
user.name # IDE знает, что это строка
# ✅ Связи между таблицами
for post in user.posts.all():
print(post.title) # Автоматическое JOIN
Недостатки ORM
# ❌ Медленнее чем чистый SQL
users = User.objects.all() # Может сделать лишний запрос
# ❌ Сложные запросы требуют знания ORM
complex_query = User.objects.filter(
Q(age__gt=25) | Q(posts__count__gt=5)
).select_related('posts').prefetch_related('comments')
# ❌ N+1 problem
users = User.objects.all()
for user in users:
print(user.posts.count()) # Запрос на каждого юзера!
# Решение: prefetch_related
users = User.objects.prefetch_related('posts')
Лучшие практики
class UserService:
def __init__(self, session):
self.session = session
def get_user_with_posts(self, user_id: int):
# ✅ Используй select_related для ForeignKey
user = self.session.query(User).filter(User.id == user_id).first()
# ✅ Используй prefetch_related для обратных связей
user.posts # Уже загружено
return user
def bulk_create(self, users_data: list):
# ✅ Для массивных операций используй bulk_create
users = [User(**data) for data in users_data]
self.session.bulk_insert_mappings(User, users)
self.session.commit()
def get_active_users(self):
# ✅ Фильтруй на уровне БД, не в Python
return self.session.query(User).filter(User.age >= 18).all()
Вывод: ORM позволяет работать с БД как с объектами Python вместо написания SQL. Лучшие ORMs для Python: SQLAlchemy (универсальный), Django ORM (встроенный), Tortoise ORM (асинхронный). Используй ORM для стандартных операций, но не забывай о сложных SQL запросах.