我正在使用Django,但在管理网站中无法正确显示某些内容时遇到了问题。这些是模型
class IndexSetSize(models.Model):
""" A time series of sizes for each index set """
index_set = models.ForeignKey(IndexSet, on_delete=models.CASCADE)
byte_size = models.BigIntegerField()
timestamp = models.DateTimeField()
class IndexSet(models.Model):
title = models.CharField(max_length=4096)
# ... some other stuff that isn't really important
def __str__(self):
return f"{self.title}"
它正在显示我需要的所有适当数据,但是,我想显示IndexSetSize的总和,按index_set键分组,还按时间戳分组(给定时间戳可能多次出现IndexSet,所以我想把所有的byte_sizes加起来。目前仅显示每条记录。另外,我希望total_size字段可排序
当前的管理员模型如下:
class IndexSetSizeAdmin(admin.ModelAdmin):
""" View-only admin for index set sizes """
fields = ["index_set", "total_size", "byte_size", "timestamp"]
list_display = ["index_set", "total_size", "timestamp"]
search_fields = ["index_set"]
list_filter = ["index_set__title"]
def total_size(self, obj):
""" Returns human readable size """
if obj.total_size:
return humanize.naturalsize(obj.total_size)
return "-"
total_size.admin_order_field = 'total_size'
def get_queryset(self, request):
queryset = super().get_queryset(request).select_related()
queryset = queryset.annotate(
total_size=Sum('byte_size', filter=Q(index_set__in_graylog=True)))
return queryset
在Django中进行分组的正确方法似乎是使用.values(),尽管如果我在get_queryset中使用它,则会抛出一个错误,提示Cannot call select_related() after .values() or .values_list()
。我无法在文档中找到是否有一种“正确”的方法来对值/注释/聚合进行处理,该方法可以与get_queryset一起正常使用。这是我尝试做的一个非常简单的按查询汇总/分组,但是我不确定用什么“ Django方式”来完成它。
谢谢
答案 0 :(得分:0)
我认为您无法返回完整的查询集并按index_set
中的get_queryset
进行分组,因为您无法选择所有列,而是按sql中的单个列进行分组
SELECT *, SUM(index_size) FROM indexsetsize GROUP BY index_set // doesn't work
您可以在total_size
方法中执行额外的查询以获取汇总值。但是,这将对返回的每一行执行查询,并降低页面加载速度。
def total_size(self, obj):
""" Returns human readable size """
return humanize.naturalsize(sum(IndexSetSize.objects.filter(
index_set=obj.index_set).values_list(
'byte_size', flat=True)))
total_size.admin_order_field = 'total_size'
最好在IndexSetAdmin
中执行此注释,因为index_set
已经通过反向外键分组了。这意味着您可以在get_queryset
中执行注释。我还将在related_name
的外键上设置IndexSetSize
,这样您就可以使用该名称从IndexSetSize
访问实际的IndexSet
对象。
class IndexSetSize(models.Model):
index_set = models.ForeignKey(IndexSet, on_delete=models.CASCADE, related_name='index_set_sizes')
...
class IndexSetAdmin(admin.ModelAdmin):
...
def total_size(self, obj):
""" Returns human readable size """
if obj.total_size:
return humanize.naturalsize(obj.total_size)
return "-"
def get_queryset(self, request):
queryset = super().get_queryset(request).prefetch_related('index_set_sizes').annotate(
total_size=Sum('index_set_sizes__byte_size')).order_by('total_size')
return queryset