首页 > 解决方案 > Django orm中的LEAD和LAG窗口功能,如何应用于单个对象?

问题描述

问题是关于WindowDjango 中的函数使用。

我有以下模型:

class EntriesChangeLog(models.Model):
    content_type = models.ForeignKey(
        ContentType,
        on_delete=models.CASCADE,
    )
    object_id = models.PositiveIntegerField(
    )
    content_object = GenericForeignKey(
        'content_type',
        'object_id',
    )
    user = models.ForeignKey(
        get_user_model(),
        verbose_name='user',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='access_logs',
    )
    access_time = models.DateTimeField(
        verbose_name='access_time',
        auto_now_add=True,
    )
    as_who = models.CharField(
        verbose_name='Status of the accessed user.',
        choices=UserStatusChoices.choices,
        max_length=7,
    )
    operation_type = models.CharField(
        verbose_name='Type of the access operation.',
        choices=OperationTypeChoices.choices,
        max_length=6,
    )
    state = JSONField(
        verbose_name='Model state before save or delete.',
        encoder=CustomEncoder,
    )

我的目标是用相同的和在查询state集中的上一个和下一个对象的字段来注释这个模型的查询集中的每个对象。这是稍后在详细视图中获取此注释并计算先前、当前和未来状态之间的差异所必需的。object_idcontent_type_id

我在 get_object 中的查询集:

def get_queryset(self):
    model = self.kwargs['model_name']
    instance_pk = self.kwargs['instance_pk']

    self.queryset = self.model.objects.filter(
        object_id=instance_pk,
        content_type__model=model.__name__.lower(),
        content_type__app_label=model._meta.app_label.lower(),
    ).select_related('user', )

    return super().get_queryset()


def get_object(self):
    queryset = self.filter_queryset(self.get_queryset())

    q = queryset.annotate(
        next_val=Window(
            expression=Lead('state'),
            order_by=F('id').asc()
        ),
        prev_val=Window(
                expression=Lag('state'),
                order_by=F('id').asc(),
        ),
    )
    obj = q.filter(pk=self.kwargs['pk']).first()

    self.check_object_permissions(self.request, obj)

    return obj

RAWSQL 中的类比

SELECT
       id,
       state,
       LEAD("state") OVER(ORDER BY "id" ) AS "next_val",
       LAG("state") OVER(ORDER BY "id") AS "prev_val"
        
FROM "administration_entrieschangelog"
where object_id =158 and content_type_id=7

当查询集中有多个对象时,它工作正常,即在 ListView 中。但在详细视图中,它似乎WHERE以前有效,SELECT并且两个注释都返回NULL。看起来WINDOW查询集中的那个函数只有一个对象,它只受这个对象的限制,LEAD并且LAG看不到它的邻居。

问题是——是否有可能以某种方式为单个对象添加这两个注释?

标签: djangodjango-rest-frameworkdjango-orm

解决方案


推荐阅读