python - Django Admin中的外键和其他字段聚合
问题描述
我在 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 可以多次出现,所以我想将所有字节大小相加)。目前只显示每条记录。此外,我希望 total_size 字段是可排序的
当前的 Admin 模型如下所示:
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 一起正常工作,我无法在文档中找到。这是一个非常简单的 sum/group by query 我正在尝试做的事情,但我不确定“Django 方式”是什么来完成它。
谢谢
解决方案
我认为您无法返回完整的查询集并分组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
外键设置为 on,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
推荐阅读
- swift - 当我离开应用程序时,如何保存我的 MapView 注释?
- javascript - 带参数的数组平均值 (...rest)
- python-3.x - 重塑的输入是具有“batch_size”值的张量,但请求的形状需要“n_features”的倍数
- powershell - Powershell 从 ForEach 导出到 Clicml
- javascript - 警告:无法在尚未安装的组件上调用 setState
- flutter - Flutter + Provider:如何将滑块的值传回提供者?
- node.js - 在 Angular 7 中访问 JSON 值
- flutter - Flutter TextFormField 掩码
- python - 有没有办法在 RPI 零上使用已编译的 keras 模型?
- c# - C# LINQ 使用值列表按子列表过滤复杂对象列表