#mysql #django #orm #prefetch #annotate
Вопрос:
# My Database Models
ModelA(models.Model):
referancer = models.CharField()
...
ModelXYZ(models.Model):
name = models.CharField()
...
У меня есть такие модели, как top, и между ними нет связи с внешним ключом, также структура должна оставаться такой, потому что в моем реальном запросе фильтры и аннотации сложнее, чем в этом. Также это самый простой способ воспроизвести проблему.
modelXYZ_subquery = ModelXYZ.objects.filter(name__exact=OuterRef('referancer')).order_by('-id')
modelA_dataset = ModelA.objects.filter(**my_custom_filters).annotate(
has_XYZ=Exists(modelXYZ_subquery),
latest_xyz=Subquery(modelXYZ_subquery.values('id')[:1], output_field=IntegerField)
)
for _modelA in modelA_dataset:
my_custom_function_1(_modelA)
if _modelA.has_XYZ:
detected_xyz = ModelXYZ.objects.get(id=_modelA.latest_xyz) # Database Hit
else:
detected_xyz = create_xyz(_modelA)
my_custom_function_2(_modelA, detected_xyz)
Это функция, которую я получил, но она работает слишком долго из-за огромного набора данных.
Я хочу избавиться от ненужного попадания в базу данных, которое я получил сверху в цикле for.
Есть ли в любом случае способ достичь этой цели с помощью аннотации или prefetch_related или чего-то еще?
Комментарии:
1. Почему же
referancer
тогда это поле не являетсяForeignKey
а ?2. Это не мой выбор, и структура базы данных должна оставаться такой. Просто желая ускорить работу, я спустился ниже.
Ответ №1:
Вы можете рассмотреть возможность использования JoinField. Это не изменит структуру вашей базы данных, но позволит ORM выполнять объединения так же, как и с внешними ключами. pip install django-joinfield
и поместите joinfield
свои установленные приложения в settings.py
from joinfield.joinfield import JoinField
class ModelXYZ(models.Model):
name = JoinField(ModelA, to_field='referancer', on_delete=models.DO_NOTHING)
миграции создадут миграцию, но миграция не изменит структуру вашей базы данных. Будет разрешено иметь значения в ModelXYZ.name которых нет в ModelA.referancer.
Теперь вы можете prefetch_related
перейти от модели к модели Xyz.
Комментарии:
1. Я буду ждать последнего дня щедрости. Если лучшего ответа нет, я отредактирую свой вопрос и одобрю его в качестве ответа, сэр.