Django ORM, как "перебазировать" QuerySet в связанную модель
В модели базы данных, описанной в упрощенном игрушечном примере ниже, мы пытаемся получить список атрибутов EAV, используемых конкретным Product
.
Приведенные ниже "Действия" выполняют указанную выше цель; однако мы считаем, что это выражение чрезмерно сложное: Выражение Python начинается с переменной template
, но аргументы значений по-прежнему должны поддерживать полный квалифицированный путь, начинающийся с исходной модели Product
.
Вместо attribute_set = template. Values("id", "template__id", "template__templateattribute__id")
, нам интересно, есть ли способ ссылаться на столбцы, как templateattribute__id
, таким образом, как "rebased" на связанную модель.
Мы будем благодарны за любые подсказки или предложения.
** Действия: **
template = Product.active_objects.filter(id='xxx').select_related('template')
attribute_set = template. Values("id", "template__id", "template__templateattribute__id")
for i, attr in enumerate(attribute_set):
print("{:03}: {}".format(i, attr))
# Output:
# Output:
# 000: {'id': xxx, 'template__id': xxxx, 'template__templateattribute__id': xxxxx}
# 001: {'id': xxx, 'template__id': xxxx, 'template__templateattribute__id': xxxxx}
# 002: {'id': xxx, 'template__id': xxxx, 'template__templateattribute__id': xxxxx}
# ...
** Пример исходного кода: **
# Simplified toy example
class Product(models.Model):
product_template = models.ForeignKey(Template)
sku = models.CharField(max_length=100)
...
class Template(models.Model):
base_sku = models.CharField(max_length=100)
...
class TemplateAttribute(models.Model):
product_template = models.ForeignKey(Template)
attribute = models.ForeignKey(eav_models.Attribute)
...
# From the open source Django EAV library
# imported as `eav_models`
#
class Attribute(models.Model):
name = models.CharField(_(u"name"), max_length=100,
help_text=_(u"User-friendly attribute name"))
...
slug = EavSlugField(_(u"slug"), max_length=50, db_index=True,
help_text=_(u"Short unique attribute label"))
...
Возможно, использование менеджера с аннотациями или псевдонимами может помочь?
Вы можете попытаться добавить больше магии, пытаясь динамически добавить аннотацию для каждого ключа во время построения менеджера, но на самом деле в этот момент вы пишете код, который должен быть в самом EAV.
Я бы предупредил вас, что наличие имен атрибутов и их значений в таблице вместо просто полей модели (и столбцов в БД) будет нелегкой битвой, и вы уже находите области, где ваша библиотека не справляется за вас.
from django.db import models
from django.db.models import F
class ProductManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset() \
.annotate(
my_attribute_key=F('template__templateattribute__id')
)
return qs
Кроме того, мы нашли обходной путь, определив базовый путь:
base = "template__templateattribute"
Так, вместо
attribute_set = template. Values("template__templateattribute__id")
, мы можем сделать следующее:
attribute_set = template. Values(base+"__id")
Однако это лишь неофициальное обходное решение. Лучшим способом по-прежнему является использование класса Manager.