Django ORM

Django ORM

monoteist

Django ORM (Object-Relational Mapping) — мощный инструмент, который позволяет взаимодействовать с базой данных, используя Python-код вместо SQL-запросов. Это значительно упрощает разработку, абстрагируя сложности работы с базами данных. Расскажу подробно о каждом аспекте:


1. Основные понятия и работа с моделями

Создание модели

Модель — это Python-класс, который наследуется от django.db.models.Model. Каждый атрибут класса соответствует полю таблицы в базе данных.

Пример:

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

Поля модели:

  • CharField: для строк (ограничение max_length обязательно).
  • IntegerField: для целых чисел.
  • TextField: для длинных текстов.
  • BooleanField: для True/False.
  • DateField, DateTimeField: для работы с датами и временем.
  • ForeignKey: связь "один ко многим".
  • ManyToManyField: связь "многие ко многим".
  • OneToOneField: связь "один к одному".

Метаданные модели

Внутренний класс Meta задаёт настройки модели:

class Author(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        db_table = 'authors'  # Имя таблицы в БД
        ordering = ['name']  # Сортировка по умолчанию

2. Управление миграциями

Миграции — механизм, который синхронизирует модели с базой данных.

Создание миграции:bash
python manage.py makemigrations

Применение миграций:bash
python manage.py migrate

Изменения моделей:

Если вы изменили модель, всегда создавайте миграции. Не меняйте структуру таблиц вручную, это нарушит синхронизацию.


3. CRUD-операции (создание, чтение, обновление, удаление)

Создание записи

author = Author(name="John Doe", age=30)
author.save()
# Или через метод create():
Author.objects.create(name="Jane Smith", age=25)

Чтение записей

  • Все записи:
authors = Author.objects.all()
  • Фильтрация:
authors = Author.objects.filter(age__gte=30)  # Возраст >= 30
  • Получение одной записи:
author = Author.objects.get(id=1)
  • ⚠️ Используйте get только если точно уверены, что запись есть в базе данных (иначе будет ошибка). Можно использовать get_object_or_404
  • Агрегации:
from django.db.models import Count, Avg

avg_age = Author.objects.aggregate(Avg('age'))

Обновление записи

author = Author.objects.get(id=1)
author.age = 35
author.save()

Или массовое обновление:

Author.objects.filter(age__lt=30).update(age=30)

Удаление записи

author = Author.objects.get(id=1)
author.delete()

Массовое удаление:

Author.objects.filter(age__lt=30).delete()

4. Связи между моделями

ForeignKey (один ко многим)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

Пример использования:

book = Book.objects.create(title="My Book", author=author)

ManyToManyField (многие ко многим)

class Publisher(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    publishers = models.ManyToManyField(Publisher)

Добавление связи:

publisher = Publisher.objects.create(name="Publisher A")
book.publishers.add(publisher)

5. Запросы: фильтрация, аннотации, агрегации

Фильтрация

  • exact: точное совпадение.
  • contains: содержит.
  • startswith, endswith: начало/окончание строки.
  • in: значение в списке.
  • gte, lte: больше/меньше или равно.

Пример:

Author.objects.filter(name__contains="John", age__gte=30)

Аннотации

Добавление вычисляемых полей:

from django.db.models import Count

authors = Author.objects.annotate(book_count=Count('book'))

6. Тонкости производительности

  1. Жадные запросы:Используйте select_related для ForeignKey.
  2. Используйте prefetch_related для ManyToManyField.

Пример:

books = Book.objects.select_related('author').all()
  1. Количество запросов: Проверьте число запросов с помощью django-debug-toolbar.
  2. Транзакции: Для сложных операций используйте atomic:
from django.db import transaction

with transaction.atomic():
    # Ваши операции

7. Управление сложными запросами

Для более сложных SQL-запросов используйте Q-объекты и F-объекты.

Q-объекты (логические условия)

from django.db.models import Q

authors = Author.objects.filter(Q(age__gte=30) | Q(name__startswith="J"))

F-объекты (сравнение полей)

from django.db.models import F

authors = Author.objects.filter(age__gte=F('book_count'))

8. Кастомизация менеджеров

Можно создать свои методы для запросов:

class AuthorManager(models.Manager):
    def young_authors(self):
        return self.filter(age__lt=30)

class Author(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

    objects = AuthorManager()

Использование:

young_authors = Author.objects.young_authors()

9. Миграции и изменение схемы базы

Если вы изменяете существующую модель (например, добавляете новое поле), убедитесь, что:

  1. Новое поле имеет default или null=True.
  2. Убедитесь, что нет данных, которые могут вызвать ошибку.

10. Сигналы Django

Позволяют реагировать на события, например, создание записи:

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Author)
def notify_author_created(sender, instance, created, **kwargs):
    if created:
        print(f"Author {instance.name} created")

11. Ограничения Django ORM

  1. Django ORM может быть медленнее, чем сырой SQL, для сложных запросов.
  2. Ограниченная поддержка операций с большим объёмом данных.
  3. Некоторые сложные запросы (например, CTE) сложнее реализовать.


Report Page