【问题标题】:Adding annotations to all querysets with a custom QuerySet as Manager使用自定义 QuerySet 作为管理器向所有查询集添加注释
【发布时间】:2017-07-20 01:38:09
【问题描述】:

我不确定如何准确地说明这一点,但我想做的是为模型使用自定义 QuerySet,但我想注释任何查询集的结果。因此,无论是应用了过滤器,还是直接获取对象(我认为最终仍然是 filter() 调用),我都希望应用注释,以便我可以在返回的模型对象中访问它们.

我当前的解决方案是使用自定义 QuerySet + 自定义管理器,自定义管理器将自定义调用传递给自定义查询集上的适当调用。当然,不幸的是,我需要在管理器和查询集之间为我想要的任何自定义方法匹配方法。

我知道 CustomQuerySet.as_manager() 的存在是为了避免这种重复,但如果我使用它,那么我将失去覆盖 get_queryset() 的能力,因此我的注释可以应用于评估查询集的所有情况。

有没有更简洁的方法来做到这一点,所以我仍然可以在最终评估查询集时链接调用并应用我的注释?

理想情况下,我希望继续使用标准调用,例如: Model.objects.most_liked().near()Model.objects.get(id=model_id)

而不是像添加一个 add_annotations() 方法到我的自定义 QuerySet 那样,因此需要在我得到模型对象的任何时候调用该方法(即,我不想要 Model.objects.get(id=id).add_annotations()Model.objects.near().add_annotations() 和等等)

但不必重复管理器和查询集之间的方法?理想情况下,不要侵入私有方法或类似的东西。我简单地玩弄了在 CustomQuerySet 类上覆盖 __iter__ 以添加注释,但这样做似乎不正确。

模型、查询集和管理器的示例设置如下。这些当然不是我真正的班级名称,只是问题的填充物。希望我已经包含了足够的内容以使我的问题可以理解:)

class CustomQuerySet(models.QuerySet):
    def most_liked(self):
        return self.filter(...)

    def near(self): 
        return self.filter(...)


class CustomManager(models.Manager):
    def get_queryset(self):
        return CustomQuerySet(self.model, using=self._db)\
            .annotate(...)\
            .annotate(...)

    def near(self, latitude, longitude, radius, max_results=100):
        return self.get_queryset().near()

    def most_liked(self):
        return self.get_queryset().most_liked()

class Model(models.Model):
    objects = CustomManager()

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    您应该使用from_queryset 方法 - 它允许您创建一个 Manager 类,您可以在应用到您的模型之前进一步自定义该类。例如:

    class CustomQuerySet(models.QuerySet):
        def most_liked(self):
            return self.filter(...)
    
    
    class CustomManager(models.Manager.from_queryset(CustomQuerySet)):
        def get_queryset(self):
            return super(CustomManager, self).get_queryset() \
                .annotate(...)
    
    
    class Model(models.Model):
        objects = CustomManager()
    

    【讨论】:

    • 太棒了,成功了!尽管我将 get_queryset() 方法保留为:def get_queryset(self): return CustomQuerySet(self.model, using=self._db)\ .annotate(...)\ .annotate(...) 您所做的更改导致了无限递归。我在 get_queryset() 中做错了什么吗?
    • 嗯,我打错了(缺少括号) - 现在对你有用吗?
    • 确实如此。也比我在那里做的更有意义。在你的帮助之前我试图让它运转的所有事情让我的大脑有点扭曲。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 2023-03-15
    • 2016-07-28
    • 2017-08-29
    • 2022-10-19
    • 1970-01-01
    相关资源
    最近更新 更多