Django включает пользовательские @свойства модели ORM в набор queryset для дальнейшего использования в фильтрах клиентов
Привет и заранее спасибо.
Я определил пользовательское свойство в моей модели ORM:
class MyModel(BaseModel):
optional_prop_1 = models.ForeignKey(Model, null=True)
optional_prop_2 = models.ForeignKey(AnotherModel, null=True)
optional_prop_2 = models.ForeignKey(DifferentModel, null=True)
@property
def external_reference(self):
if self.optional_prop_1:
return self.optional_prop_1
if self.optional_prop_2:
return self.optional_prop_2
...
Все эти три поля имеют общее поле, к которому я хочу получить доступ внутри моего пользовательского запроса filer, но поскольку external_reference
определено как "виртуальное" свойство, я знаю, что не могу получить к нему доступ внутри queryset, поэтому, когда я делаю это, это действительно работает:
queryset.filter(top_level_relation__my_model__external_reference__common_field="some_value")
Кажется, я понял, что мне нужно как-то преобразовать мое "виртуальное" свойство в поле динамически с помощью пользовательских models.Manager
и queryset.annotate()
, но, похоже, это не работает. Я попробовал следующее:
def _get_external_reference(model) -> str:
if model.optional_prop_1:
return "optional_prop_1"
elif model.optional_prop_2:
return "optional_prop_1"
...
return ""
def get_queryset(self):
external_reference = _get_external_reference(self.model)
return super().get_queryset().annotate(external_reference=models.F(external_reference))
Но внутри моего пользовательского фильтра я всегда получаю Related Field got invalid lookup: external_reference
говоря мне, что это поле не существует в наборе запросов. Есть идеи, как преобразовать свойство (@property) в поле, которое я мог бы использовать позже внутри queryset
Ошибка в вашем коде заключается в том, что вы пытаетесь получить доступ к свойствам модели непосредственно в функции _get_external_reference, но аргументом, передаваемым этой функции, является не экземпляр MyModel, а сам класс модели.
Кроме того, возвращаемое значение _get_external_reference
является строкой, представляющей имя свойства, но вы используете эту строку непосредственно в вызове annotate в качестве имени поля.
Для решения этой проблемы можно использовать выражения Func
и F
для динамического создания выражения для аннотированного поля на основе значений полей optional_prop_1, optional_prop_2 и optional_prop_3:
from django.db.models import F, Func, Value
class MyModelManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
external_reference=Func(
F('optional_prop_1'),
F('optional_prop_2'),
F('optional_prop_3'),
function='COALESCE',
output_field=models.ForeignKey(Model),
)
)
class MyModel(BaseModel):
...
objects = MyModelManager()
class Meta:
...