【问题标题】:Django ORM - Get Max group byDjango ORM - 获取最大组
【发布时间】:2017-07-31 10:04:31
【问题描述】:

我有三个模型。

数据中心

class Datacenter(models.Model):
    """
    Datacenter
    """

    uuid = models.UUIDField(verbose_name=_('UUID'), unique=True, default=uuid.uuid1, editable=False)
    name = models.CharField(_('name'), max_length=80, db_index=True)
    price_per_gigabyte = models.DecimalField(_('price per gigabyte'), max_digits=36, decimal_places=18, default=0, db_index=True)

    class Meta:
        verbose_name = _('datacenter')
        verbose_name_plural = _('datacenters')
        ordering = ['name']

    def __str__(self):
        return f'{self.name} / ${self.price_per_gigabyte:.2f} per GB'

服务器

class Server(models.Model):
    """
    Server
    """

    uuid = models.UUIDField(verbose_name=_('UUID'), unique=True, default=uuid.uuid1, editable=False)
    hostname = models.CharField(_('hostname'), max_length=253, db_index=True)
    datacenter = models.ForeignKey(Datacenter, models.PROTECT, related_name="servers", related_query_name="server", verbose_name=_('datacenter'))
    useful_storage_capacity = models.PositiveSmallIntegerField(_('useful storage capacity'), default=0, db_index=True)

    class Meta:
        verbose_name = _('server')
        verbose_name_plural = _('servers')
        ordering = ['hostname']

    def __str__(self):
        return self.hostname

存储

class Storage(models.Model):
    """
    Storage Resource
    """

    uuid = models.UUIDField(verbose_name=_('UUID'), unique=True, default=uuid.uuid1, editable=False)
    server = models.ForeignKey(Server, models.PROTECT, related_name="storages", related_query_name="storage", verbose_name=_('server'))
    project = models.ForeignKey(Project, models.PROTECT, related_name="storages", related_query_name="storage", verbose_name=_('project'))
    space_used_latest_copy = models.PositiveSmallIntegerField(_('space used latest copy'), db_index=True)
    space_used_repository = models.PositiveSmallIntegerField(_('space used repository'), db_index=True)
    space_used_other = models.PositiveSmallIntegerField(_('space used other'), db_index=True)

    class Meta:
        verbose_name = _('storage resource')
        verbose_name_plural = _('storage resources')
        unique_together = (('server', 'project'),)
        ordering = ['server', 'project']

    def __str__(self):
        return f'{self.uuid} ({self.project}/{self.server})'

    def get_space_used_total(self):
        return self.space_used_latest_copy + self.space_used_repository + self.space_used_other

数据中心可以有许多服务器。从存储模型我可以得到服务器上使用了多少空间。

我需要获得数据中心最空闲的空间服务器(只有一个)。

这是目前拥有的:

servers = Server.objects.all() \
            .annotate(free=F('useful_storage_capacity') - Coalesce(Sum('storage__space_used_latest_copy'), V(0)) - Coalesce(Sum('storage__space_used_repository'), V(0))
                      - Coalesce(Sum('storage__space_used_other'), V(0))) \
            .filter(free__gte=space_prepaid) \
            .order_by('-free') 

我注释了包含服务器可用空间的字段“空闲”。我需要以某种方式按数据中心对其进行分组并获得最大的免费价值。所以最后我从每个数据中心获得了一台也是最免费的服务器。

找不到任何正确方法的示例。有什么解决办法?

谢谢!

【问题讨论】:

  • 你应该在某个地方有一个“存储”模型,你在查询中引用它,但我在代码中找不到任何提示。
  • 是的,抱歉,已更新

标签: python django django-orm


【解决方案1】:

您需要使用values or values_list 进行 GROUP BY 查询。

servers = Server.objects.all() \
            .values('datacenter__uuid', 'id') \
            .annotate(free=F('useful_storage_capacity') - Coalesce(Sum('storage__space_used_latest_copy'), V(0)) - Coalesce(Sum('storage__space_used_repository'), V(0))
                      - Coalesce(Sum('storage__space_used_other'), V(0))) \
            .annotate(max_free=Max(F('free'))
            .filter(free__gte=space_prepaid, free=F('max_free')) \
            .values('datacenter__uuid', 'id', 'free')
            .order_by('-free') 

我认为这应该为每个数据中心提供最免费的服务器。 .values, .filter, and .annotate matter 的排序,所以这可能会有点棘手。尝试使用这些方法。

【讨论】:

  • 我在服务器模型中没有服务器字段。也许是另一种方式?
  • 对不起,我的错误,我将它更新为按 id 分组,因此它显示每个服务器的可用存储空间。
  • 不,我不是这个意思。我需要按数据中心分组并获得最免费的服务器。
  • 您能看一下更新后的答案并试一试吗?它有点复杂,因此您可能不得不尝试使用 .values、.filter 和 .annotate 方法的组合和技术。
  • 按照您的建议尝试了非常相似的方式。它说:无法计算 Max('free'):'free' 是一个聚合
猜你喜欢
  • 2013-07-27
  • 2019-02-18
  • 2013-11-24
  • 2019-10-11
  • 1970-01-01
  • 2022-11-17
  • 2010-10-30
  • 2022-01-15
相关资源
最近更新 更多