【问题标题】:Get data in model methods from multiple models - Django从多个模型中获取模型方法中的数据 - Django
【发布时间】:2018-07-02 10:49:21
【问题描述】:

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

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

要根据前两个模型数据获取另一个表,我可以创建一个新模型,该模型仅使用 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 模型的字符串表示,可用的库存应该计算为:

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

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

【问题讨论】:

  • 该链接问题中没有任何内容涉及创建单独的模型。但你不需要;您可以通过 related_name 获取 Sold 和 FinishedGoodsItems 的集合。

标签: python django django-models django-admin


【解决方案1】:

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

示例代码(可能不是 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

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

【讨论】:

  • 感谢您的回答。你能解释一下这里finished_name和sold_name指的是什么吗?正如我之前所说,我对 Python 和 Django 都是新手,所以这可能是一个愚蠢的问题。
  • finished_name 和 sold_name 是您在参数 related_name 的模型定义中指定的反向引用名称。
  • 如我所见,finished_name 和sold_name 不是GoodsItem 类的成员,那么我们如何在stock_available 的stock_available 方法中像self.finished_name 那样访问它们?
  • 当我使用你提供的第二个示例代码时,我得到了不正确的stock_available,为什么?
猜你喜欢
  • 2020-09-19
  • 2017-11-25
  • 1970-01-01
  • 2011-11-04
  • 2016-08-11
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多