Введение в Django ORM
Django ORM (Object-Relational Mapping) - это система, которая позволяет работать с базами данных используя Python объекты вместо SQL запросов. ORM автоматически преобразует операции с объектами в SQL запросы.
Поддерживаемые базы данных
Django поддерживает:
- PostgreSQL
- MySQL
- SQLite (по умолчанию)
- Oracle
- SQL Server
Настройка базы данных
В settings.py:
1
2
3
4
5
6
7
8
9
10
| DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydatabase',
'USER': 'mydatabaseuser',
'PASSWORD': 'mypassword',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
|
Создание моделей
Модели определяют структуру данных:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
def __str__(self):
return self.name
class Meta:
verbose_name = 'Категория'
verbose_name_plural = 'Категории'
class Article(models.Model):
STATUS_CHOICES = [
('draft', 'Черновик'),
('published', 'Опубликовано'),
]
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
published_at = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.title
class Meta:
ordering = ['-created_at']
verbose_name = 'Статья'
verbose_name_plural = 'Статьи'
|
Типы полей
CharField - строкаTextField - длинный текстIntegerField - целое числоDecimalField - десятичное числоBooleanField - булево значениеDateTimeField - дата и времяForeignKey - внешний ключManyToManyField - многие ко многимOneToOneField - один к одному
Миграции
Создание миграций
1
2
| python manage.py makemigrations
python manage.py makemigrations myapp
|
Применение миграций
1
| python manage.py migrate
|
Откат миграций
1
| python manage.py migrate myapp 0001
|
Основные запросы ORM
Создание объектов
1
2
3
4
5
6
7
8
9
10
11
| # Создание и сохранение
category = Category(name='Python', slug='python')
category.save()
# Создание с помощью create()
article = Article.objects.create(
title='Заголовок статьи',
content='Содержание статьи',
author=request.user,
category=category
)
|
Получение объектов
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Получить все объекты
articles = Article.objects.all()
# Получить один объект
article = Article.objects.get(id=1)
# Получить или создать
article, created = Article.objects.get_or_create(
title='Новая статья',
defaults={'content': 'Содержание', 'author': request.user}
)
# Получить первое/последнее
first_article = Article.objects.first()
last_article = Article.objects.last()
|
Фильтрация
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # Фильтр по полю
published_articles = Article.objects.filter(status='published')
# Исключение
draft_articles = Article.objects.exclude(status='published')
# Сложные условия
articles = Article.objects.filter(
status='published',
created_at__year=2023
)
# Поиск по тексту
articles = Article.objects.filter(title__icontains='python')
# Фильтр по связанным объектам
user_articles = Article.objects.filter(author__username='john')
|
Операторы запросов
__exact - точное совпадение__icontains - содержит (регистронезависимо)__startswith - начинается с__endswith - заканчивается на__gt - больше__gte - больше или равно__lt - меньше__lte - меньше или равно__in - в списке__range - в диапазоне__year, __month, __day - для дат
Сортировка и ограничение
1
2
3
4
5
6
7
8
9
| # Сортировка
articles = Article.objects.order_by('-created_at')
articles = Article.objects.order_by('title', '-created_at')
# Ограничение количества
recent_articles = Article.objects.order_by('-created_at')[:5]
# Обратная сортировка
articles = Article.objects.order_by('-created_at').reverse()
|
Агрегация и аннотация
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| from django.db.models import Count, Sum, Avg, Max, Min
# Подсчет
total_articles = Article.objects.count()
category_count = Article.objects.values('category__name').annotate(count=Count('id'))
# Сумма, среднее и т.д.
from django.db.models import Sum
total_views = Article.objects.aggregate(Sum('views'))['views__sum']
# Аннотация
articles_with_comment_count = Article.objects.annotate(
comment_count=Count('comments')
)
|
Обновление объектов
1
2
3
4
5
6
7
8
9
10
11
| # Обновление одного объекта
article = Article.objects.get(id=1)
article.title = 'Новый заголовок'
article.save()
# Обновление нескольких объектов
Article.objects.filter(status='draft').update(status='published')
# Обновление с F-выражениями
from django.db.models import F
Article.objects.filter(id=1).update(views=F('views') + 1)
|
Удаление объектов
1
2
3
4
5
6
| # Удаление одного объекта
article = Article.objects.get(id=1)
article.delete()
# Удаление нескольких объектов
Article.objects.filter(status='draft').delete()
|
Работа со связанными объектами
Foreign Key
1
2
3
4
5
6
7
8
| # Получение связанных объектов
article = Article.objects.get(id=1)
author = article.author # Получить автора
category = article.category # Получить категорию
# Обратная связь
user = User.objects.get(username='john')
user_articles = user.article_set.all() # Все статьи пользователя
|
Many-to-Many
1
2
3
4
5
6
7
8
9
10
11
12
| # Добавление связи
article.tags.add(tag1, tag2)
# Удаление связи
article.tags.remove(tag1)
# Установка связей
article.tags.set([tag1, tag3])
# Проверка связи
if article.tags.filter(name='python').exists():
pass
|
1
2
3
4
5
6
7
8
| # select_related для Foreign Key (один запрос)
articles = Article.objects.select_related('author', 'category').all()
# prefetch_related для Many-to-Many (два запроса)
articles = Article.objects.prefetch_related('tags').all()
# Комбинирование
articles = Article.objects.select_related('author').prefetch_related('tags').all()
|
Raw SQL запросы
1
2
3
4
5
6
7
8
9
| from django.db import connection
# Raw SQL
articles = Article.objects.raw('SELECT * FROM myapp_article WHERE status = %s', ['published'])
# Прямой SQL
with connection.cursor() as cursor:
cursor.execute("SELECT COUNT(*) FROM myapp_article")
row = cursor.fetchone()
|
Оптимизация запросов
Использование индексов
1
2
3
| class Article(models.Model):
title = models.CharField(max_length=200, db_index=True)
created_at = models.DateTimeField(db_index=True)
|
Кеширование запросов
1
2
3
4
5
6
7
8
9
10
11
| from django.core.cache import cache
def get_popular_articles():
cache_key = 'popular_articles'
articles = cache.get(cache_key)
if articles is None:
articles = Article.objects.filter(status='published').order_by('-views')[:10]
cache.set(cache_key, articles, 3600) # Кеш на 1 час
return articles
|
Заключение
Django ORM предоставляет мощный и удобный интерфейс для работы с базами данных. Он позволяет писать меньше кода, автоматически генерирует SQL и предоставляет множество инструментов для оптимизации запросов. Понимание основных концепций ORM поможет вам эффективно работать с данными в Django проектах.