【问题标题】:Annotate using an extra field from a ManyToMany model in Django在 Django 中使用 ManyToMany 模型中的额外字段进行注释
【发布时间】:2013-02-25 15:20:49
【问题描述】:

直截了当:
模型:

class Shop(models.Model):
    name = models.CharField(max_length=255)        

class Product(models.Model):
    name = models.CharField(max_length=255)
    shops = models.ManyToManyField(Shop, through='ProductShop', related_name='products')

class ProductShop(models.Model):
    product = models.ForeignKey(Product)
    shop = models.ForeignKey(Shop)
    price = models.DecimalField(max_digits=20, decimal_places=2)

现在我想获取所有销售该产品的商店中按最低价格订购的产品列表。我一直使用annotate 进行此类查询,但在这里我想不出任何解决方案。这大概是我想要得到的:

products = Product.objects.annotate(price=SOMETHING_TO_GET_THE_LOWEST_PRICE_PER_PRODUCT).order_by('price')

有什么好的解决方案吗?我知道extra,但不想写普通的SQL。我尽力寻找答案,但无法通过 Google 搜索我的具体问题。

谢谢!

【问题讨论】:

    标签: python django model many-to-many


    【解决方案1】:

    你的意思是:

    products = ProductShop.objects.filter(
       shop__in=Shop.objects.filter()).annotate(Min(price)).order_by('price')
    
    {% for ps in productshop %}
        Shop: {{ ps.product.shop }}
        Product: {{ ps.product }}
        Minimum Price: {{ ps.price }}
    {% endfor %}
    

    【讨论】:

    • 似乎不起作用。首先,它会返回 ProductShops,而不是 Products,对吗?其次,如果你不给任何东西赋值,注释有什么用?我只是无法理解它是如何工作的,而从我在 CLI 中的测试来看,它没有。
    • 它会返回产品。请记住 productshop 有 product 的外键,因此您可以通过 {{shop.product.name}} 访问它
    • 现在,在将注释更正为 Min('price') 后,它返回 ProductShop 对象,按价格排序。我看不出如何使它成为商店列表,我想它需要一些“不同的”或其他东西。但是在正常的 for 循环中,将那些 ProductShops 变成 Shops 应该很容易。不过,我更喜欢我的解决方法。无论如何,感谢您的贡献! :)
    • 嗯,很容易记住productshop有一个产品外键,所以你可以简单地{% for ps in productshop %}{{ps.product.shop}}{% endfor %},就是这样
    • 这行不通,但我明白你在想什么。首先,Product 没有名为“shop”的字段(您的查询不起作用)。其次,我写了“我想获取产品列表”,所以在这里{{ps.product}} 就可以了。但是,正如我所说,它可以多次给我同样的产品。假设我有一个产品p1 由两家商店s1s2 销售。我将有两个 ProductShop 对象(ps1ps2),它们都会在 ps1.productps2.product 中产生相同的 p1 产品@
    【解决方案2】:

    最后通过一个小解决方法解决了它:

    class Product(models.Model):
        name = models.CharField(max_length=255)
        shops = models.ManyToManyField(Shop, through='ProductShop', related_name='products')
        def lowest_possible_price(self):
            shops = self.shops.all()
            if not shops:
                return "N/A"
            return reduce(lambda x, y: min(x, ProductShop.objects.get(shop__pk=y.id, product__pk=self.id).price), 
                    shops, ProductShop.objects.get(shop__pk=shops[0].id, product__pk=self.id).price)
    


    products = sorted(Product.objects.all(),
            key = lambda product : product.lowest_possible_price())
    

    如果有没有辅助功能的单行解决方案,我仍然会感到困扰(lowest_possible_price 这里)

    【讨论】:

      猜你喜欢
      • 2012-02-04
      • 2018-12-04
      • 2016-11-10
      • 1970-01-01
      • 2011-08-27
      • 1970-01-01
      • 1970-01-01
      • 2019-01-22
      • 1970-01-01
      相关资源
      最近更新 更多