python Django将ORM模型上的custom @property包含到queryset中,以备将来在客户过滤器中使用

rsl1atfo  于 2023-02-07  发布在  Python
关注(0)|答案(1)|浏览(93)

我已经在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
    ...

所有这三个字段都有一个公共字段,我想在我的自定义过滤器查询中访问它,但是因为external_reference被定义为“虚拟”属性,所以我知道我不能在queryset中访问它,所以当我这样做时,它实际上不起作用:

queryset.filter(top_level_relation__my_model__external_reference__common_field="some_value")

我想我有一个想法,我需要以某种方式将我的“虚拟”属性转换为一个字段动态与自定义models.Managerqueryset.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总是告诉我这个字段在queryset中不存在。你知道如何将property(@property)转换成一个字段,以便我以后在queryset中使用吗

waxmsbnn

waxmsbnn1#

代码中的错误在于,您试图直接在_get_external_reference函数中访问模型的属性,但传递给此函数的参数不是MyModel的示例,而是模型类本身。
另外,_get_external_reference的返回值是一个表示属性名称的字符串,但是您在注解调用中直接使用该字符串作为字段名称。
要解决此问题,您可以使用FuncF表达式,根据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:
        ...

相关问题