У меня есть пользователи, которые создают (или получают) транзакции. У меня есть иерархия транзакций, состоящая из нескольких таблиц, с Transaction
в качестве базовой модели, содержащей общие поля для всех типов транзакций, таких как Пользователь (FK), сумма и т. Д. c. У меня есть несколько типов транзакций, которые расширяют модель Transaction
с указанием типа c data.
Ради этого примера ниже приведена упрощенная структура, иллюстрирующая мою проблему.
from model_utils.managers import InheritanceManager
class User(models.Model):
pass
class Transaction(models.Model):
DEPOSIT = 'deposit'
WITHDRAWAL = 'withdrawal'
TRANSFER = 'transfer'
TYPES = (
(DEPOSIT, DEPOSIT),
(WITHDRAWAL, WITHDRAWAL),
(TRANSFER, TRANSFER),
)
type = models.CharField(max_length=24, choices=TYPES)
user = models.ForeignKey(User)
amount = models.PositiveIntegerField()
objects = InheritanceManager()
class Meta:
indexes = [
models.Index(fields=['user']),
models.Index(fields=['type'])
]
class Withdrawal(Transaction):
TYPE = Transaction.WITHDRAWAL
bank_account = models.ForeignKey(BankAccount)
class Deposit(Transaction):
TYPE = Transaction.DEPOSIT
card = models.ForeignKey(Card)
class Transfer(Transaction):
TYPE = Transaction.Transfer
recipient = models.ForeignKey(User)
class Meta:
indexes = [
models.Index(fields=['recipient'])
]
Затем я устанавливаю тип каждой транзакции в методе .save()
унаследованной модели. Это все хорошо и хорошо.
Проблема возникает, когда я хочу получить транзакции пользователя. В частности, мне требуются экземпляры подмодели (депозиты, переводы и снятие средств), а не базовая модель (транзакции). Мне также требуются транзакции, которые пользователь создал сам, и переводы, которые он получил. Для первого я использую django-model-utils
's fantasti c IneritanceManager
, который прекрасно работает. За исключением того, что когда я включаю фильтрацию в поле FK получателя подмодели переноса, запрос БД увеличивается на порядок.
Как показано выше, я поместил индексы в столбец Транзакция user
и Перевод recipient
колонка. Но мне показалось, что мне может понадобиться индекс подтипа Transaction, если это вообще возможно. Я попытался добиться этого эффекта, поместив индекс в поле «Транзакция type
» и включив его в запрос, как вы увидите ниже, но, похоже, это не имеет никакого эффекта. Кроме того, я использую .select_related()
для пользовательских объектов, поскольку они требуются для сериализации.
Запрос структурирован следующим образом:
from django.db.models import Q
queryset = Transaction.objects.select_related(
'user',
'transfer__recipient'
).select_subclasses().filter(
Q(user=request.user) |
Q(type=Transaction.TRANSFER, transfer__recipient=request.user)
).order_by('-id')
Так что мой вопрос: почему существует разница в величине в запросе БД при включении Transfer.recipient
в запрос? Я что-то пропустил? Я делаю что-то глупое? Или есть способ, которым я могу оптимизировать это дальше?