如何基于其他非相关模型过滤Django模型

时间:2019-02-28 11:42:49

标签: python django

请参考下面的代码

交易模型

class Transaction(models.Model)
    current_product_code = models.CharField(....)
    previous_product_code = models.CharField(....)
    @property
    def status(self):
        c_price = Product.objects.get(code=self.current_product_code).price
        p_price = Product.objects.get(code=self.previous_product_code).price
        if c_price == p_price:
            return "Due"
        elif c_price > p_price:
            return "Upgrade"
        else:
            return "Downgrade"

产品型号

class Product(models.Model):
    code = models.CharField(....)
    price = models.DecimalField(....)

我的问题:我如何获取/过滤具有升级/降级/到期状态的交易。我正在尝试创建一个自定义管理员过滤器,该过滤器根据其状态过滤事务,但是我无法放入.filter()里面的内容,请检查下面的方法

def queryset(self, request, queryset):
    value = self.value()
    if value == 'Upgrade':
        return queryset.filter(***** HERE *****)
    elif value == 'Downgrade':
        return queryset.filter(***** HERE *****)
    elif value == 'Unknown':
        return queryset.filter(***** HERE *****)
        return queryset

3 个答案:

答案 0 :(得分:2)

您确实应该在ForeignKeyProduct之间使用Transaction(对于current_product_codeprevious_product_code两者)。这将使您可以轻松地在查询集中使用这些关系。

我建议的模型结构如下:

class Product(models.Model):
    code = models.CharField(....)
    price = models.DecimalField(....)


class Transaction(models.Model)
    # You have to define related_name for at least one of relations below.
    # Without that, automatically generated ones will clash.
    # Also don't foget to change `on_delete` to suit your needs.
    current_product = models.ForeignKey(Product, related_name="current_transactions", on_delete=models.CASCADE)
    previous_product = models.ForeignKey(Product, related_name="previous_transactions", on_delete=models.CASCADE)

    @property
    def status(self):
        # also, no need to do additional queries here manually. You can improve
        # it further by using `select_related` when querying for transactions.
        c_price = self.current_product.price
        p_price = self.previous_product.price
        if c_price == p_price:
            return "Due"
        elif c_price > p_price:
            return "Upgrade"
        else:
            return "Downgrade"

使用该模型结构,查找特定类型的交易将更加容易:

upgrade_transactions = Transaction.objects.filter(current_product__price__gt=F('previous_product__price'))
downgrade_transactions = Transaction.objects.filter(current_product__price__lt=F('previous_product__price'))
due_transactions = Transaction.objects.filter(current_product__price=F('previous_product__price'))

答案 1 :(得分:1)

我认为您可以尝试使用Subquery, OuterRef.annotate()

if value == 'Upgrade':
    return queryset.annotate(
        previous_price=Subquery(
            Product.objects.filter(
                code=OuterRef("previous_product_code")
            )[:1]
        ),
        current_price=Subquery(
            Product.objects.filter(
                code=OuterRef("current_product_code")
            )[:1]
        ),
    ).filter(current_price__gt=F("previous_price"))
...

答案 2 :(得分:0)

请记住,最后,filter()操作是一个SQL操作,我们应该注意性能问题。

因此,我的建议是:如果您需要按状态进行过滤,则每次保存交易时都要更新产品模型上的状态。您的应用程序将更快并且代码更简洁。