从多个模型中获取模型方法中的数据 - Django

时间:2018-01-23 15:00:46

标签: python django django-models django-admin

我对Django(Python也是)很陌生,并且通过实践来学习它。

我正在玩Django管理站点。我创建了两个模型并在admin中成功注册。 list_display中给出的字段可以很好地显示数据。 我想要一个admin中的另一个表,它通过一些逻辑处理来显示来自两个表的数据。

要根据前两个模型数据获取另一个表,我可以使用此question中提到的方法创建一个新模型。

现在的问题是,如何从其他模型表中获取数据以及如何返回,以便可以在admin中的表中显示。

这是我的models.py:

from django.db import models


class GoodsItem(models.Model):
    name = models.CharField(max_length=255)
    size = models.DecimalField(max_digits=4, decimal_places=2)
    INCHES = 'IN'
    NUMBER = 'NUM'
    GOODS_ITEM_SIZE_UNITS = (
        (INCHES, 'Inches'),
        (NUMBER, '#'),
    )
    size_unit = models.CharField(
        max_length=4,
        choices=GOODS_ITEM_SIZE_UNITS,
        default=INCHES,
    )

    def __str__(self):
        if(self.size_unit == self.NUMBER):
            return "%s #%s" % (self.name, (self.size).normalize())
        else:
            return "%s %s\"" % (self.name, (self.size).normalize())


class FinishedGoodsItem(models.Model):
    date = models.DateField()
    goods_item = models.ForeignKey(GoodsItem, on_delete=models.CASCADE, related_name="finished_name")
    weight = models.DecimalField(max_digits=6, decimal_places=3)

    def __str__(self):
        return str(self.goods_item)


class SoldGoodsItem(models.Model):
    goods_item = models.ForeignKey(GoodsItem, on_delete=models.CASCADE, related_name="sold_name")
    date = models.DateField()
    weight = models.DecimalField(max_digits=6, decimal_places=3)

    def __str__(self):
        return self.goods_item

admin中的第三个表应显示如下数据:

===============================
GoodsItem   |   Stock Available
===============================

此处GoodsItem是GoodsItem模型的字符串表示形式,可用库存应计算为:

FinishedGoodsItem中特定GoodsItem的重量总和,直到最后一个条目(即最后进入日期) - SoldGoodsItem中特定GoodsItem的重量总和,直到最后一个条目(即最后进入日期)

我将实现逻辑,如果某种个性告诉我如何查询数据并通过模型中的不同方法返回。如果有任何疑问,请随时提出。

1 个答案:

答案 0 :(得分:1)

据我所知,每个GoodsItem对象需要一行。您可以将“库存可用”列直接添加到GoodsItem管理员,而无需创建单独的模型,正如Daniel Roseman所说。

示例代码(可能不是100%正确,但您明白了):

class GoodsItem(models.Model):
    # ...
    @property
    def stock_available(self):
        stock_finished = self.finished_name.aggregate(Sum('weight'))['weight__sum']
        stock_sold = self.sold_name.aggregate(Sum('weight'))[
            'weight__sum']
        return stock_finished - stock_sold


class GoodsItemAdmin(admin.ModelAdmin):
    # ...
    list_display = ('name', 'size', 'size_unit', 'stock_available')

请参阅Django docs on aggregation。请记住,这将对列表中显示的每个项目执行两次额外查询。

编辑: 下面提出的解决方案不起作用,因为Django错误包含聚合和多个表here,如一条评论。请改用使用子查询的this answer

如果先前的解决方案由于许多查询而太慢,则另一个选项是:

class GoodsItemAdmin(admin.ModelAdmin):
    list_display = ('name', 'size', 'size_unit', 'stock_available')

    def get_queryset(self, request):
        qs = super(GoodsItemAdmin, self).get_queryset(request)
        qs = qs.annotate(stock_available=Sum('finished_name__weight') - Sum('sold_name__weight'))
        return qs

请注意,最后一个选项仅将功能添加到管理员,但这可能就足够了。