在每个类别的查询集中过滤 X 个最近的条目
Filtering X most recent entries in each category of queryset
问题是关于在每个查询集类别中过滤 X 个最近的条目。
目标是这样的:
我有一个基于以下模型的传入查询集。
class UserStatusChoices(models.TextChoices):
CREATOR = 'CREATOR'
SLAVE = 'SLAVE'
MASTER = 'MASTER'
FRIEND = 'FRIEND'
ADMIN = 'ADMIN'
LEGACY = 'LEGACY'
class OperationTypeChoices(models.TextChoices):
CREATE = 'CREATE'
UPDATE = 'UPDATE'
DELETE = 'DELETE'
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,
)
我需要以这种方式过滤这个传入的查询集,以便在每个类别中只保留 4 个最近的对象(由 access_time
字段定义)。类别由“content_type_id
”字段定义,有 3 个可能的选项。
让我们称之为“option1
”、“option2
”和“option3
”
此传入查询集可能包含不同数量的 1,2 类或所有 3 类对象。这是事先无法预测的。
DISTINCT
无法使用,因为过滤操作后可能会对该查询集进行排序。
我通过以下方式设法获得了 1 个最新的对象:
# get one most recent operation in each category
last_operation_time = Subquery(
EntriesChangeLog.objects.filter(user=OuterRef('user')).values('content_type_id').
annotate(last_access_time=Max(‘access_time’)).values_list('last_access_time', flat=True)
)
queryset.filter(access_time__in=last_operation_time)
但我很难弄清楚如何获取最后 4 个最近的对象而不是最后一个。
这是 Django-Filter 所必需的,并且需要在一个查询中完成。
DB-Postgres 12
你知道如何进行这种过滤吗?
谢谢...
pk_to_rank = queryset.annotate(rank=Window(
expression=DenseRank(),
partition_by=('content_type_id',),
order_by=F('access_time').desc(),
)).values_list('pk', 'rank', named=True)
pks_list = sorted(log.pk for log in pk_to_rank if log.rank <= value)
return queryset.filter(pk__in=pks_list)
通过将查询集分成两部分来设法做到这一点。带有 3 个联合的选项也是可能的,但是如果我们有 800 个选项而不是 3 - 使 800 个联合()怎么办???不...
问题是关于在每个查询集类别中过滤 X 个最近的条目。
目标是这样的:
我有一个基于以下模型的传入查询集。
class UserStatusChoices(models.TextChoices):
CREATOR = 'CREATOR'
SLAVE = 'SLAVE'
MASTER = 'MASTER'
FRIEND = 'FRIEND'
ADMIN = 'ADMIN'
LEGACY = 'LEGACY'
class OperationTypeChoices(models.TextChoices):
CREATE = 'CREATE'
UPDATE = 'UPDATE'
DELETE = 'DELETE'
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,
)
我需要以这种方式过滤这个传入的查询集,以便在每个类别中只保留 4 个最近的对象(由 access_time
字段定义)。类别由“content_type_id
”字段定义,有 3 个可能的选项。
让我们称之为“option1
”、“option2
”和“option3
”
此传入查询集可能包含不同数量的 1,2 类或所有 3 类对象。这是事先无法预测的。
DISTINCT
无法使用,因为过滤操作后可能会对该查询集进行排序。
我通过以下方式设法获得了 1 个最新的对象:
# get one most recent operation in each category
last_operation_time = Subquery(
EntriesChangeLog.objects.filter(user=OuterRef('user')).values('content_type_id').
annotate(last_access_time=Max(‘access_time’)).values_list('last_access_time', flat=True)
)
queryset.filter(access_time__in=last_operation_time)
但我很难弄清楚如何获取最后 4 个最近的对象而不是最后一个。 这是 Django-Filter 所必需的,并且需要在一个查询中完成。
DB-Postgres 12
你知道如何进行这种过滤吗?
谢谢...
pk_to_rank = queryset.annotate(rank=Window(
expression=DenseRank(),
partition_by=('content_type_id',),
order_by=F('access_time').desc(),
)).values_list('pk', 'rank', named=True)
pks_list = sorted(log.pk for log in pk_to_rank if log.rank <= value)
return queryset.filter(pk__in=pks_list)
通过将查询集分成两部分来设法做到这一点。带有 3 个联合的选项也是可能的,但是如果我们有 800 个选项而不是 3 - 使 800 个联合()怎么办???不...