Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django:property和queryset具有完全相同角色的干代码?_Python_Django_Django Models - Fatal编程技术网

Python Django:property和queryset具有完全相同角色的干代码?

Python Django:property和queryset具有完全相同角色的干代码?,python,django,django-models,Python,Django,Django Models,在Django代码中,对于OrderedArticle对象,我需要计算一个hist\u price,它是两个字段的乘积:hist\u unit\u price*quantity 我做这件事的第一个方法是一个简单的属性: class OrderedArticle(Model): @property def hist_price(self): return self.hist_unit_price * self.quantity 然后,我意识到,当我需要对这些价格进

在Django代码中,对于
OrderedArticle
对象,我需要计算一个
hist\u price
,它是两个字段的乘积:
hist\u unit\u price
*
quantity

我做这件事的第一个方法是一个简单的属性:

class OrderedArticle(Model):
    @property
    def hist_price(self):
        return self.hist_unit_price * self.quantity
然后,我意识到,当我需要对这些价格进行大量计算时,出于性能原因,我不能使用此属性,相反,我必须在数据库级别计算历史价格。这就是我为此编写自定义查询集的原因:

class OrderOperationQuerySet(Queryset):

    @staticmethod
    def _hist_price(orderable_field):  # can be an OrderedArticle or another object here
        return ExpressionWrapper(
            F(f'{orderable_field}__hist_unit_price') * F(f'{orderable_field}__quantity'),
            output_field=DecimalField())
目前,我的代码中使用了
hist_price
属性和
\u hist_price
queryset

问题

这很有效,但我很恼火,因为我两次编写相同的业务逻辑。我有一种感觉,我在这里做的不是“正确的方式”。 我认为我应该在代码级别上确保,无论我使用属性还是queryset,它都会返回相同的结果。 在这个特定的例子中,业务逻辑是两个小数之间的简单乘法,所以应该可以,但我的代码中还有其他更复杂的情况

你看到改进我的代码的方法了吗?谢谢

这个想法与之前的想法类似-我对来自线程链的任何答案都不太满意(比如将计算出的值存储在表上的一个额外字段中,并始终确保更新)

您的属性和ExpressionWrapper函数都可以使用一些内部函数,只要所需的运算符重载以接受实际值或
F()
对象(例如基本数学运算符)

如果在其中一个混合函数中,它变得比基本的数字操作更复杂,并且您希望避免重复的业务逻辑,那么您需要编写一个包装器func,它可以使用python函数为属性调用方解析到正确的输出,以及可以对查询集调用者的F对象进行操作以保持运算符重载的函数。但这将导致代码内省参数,以确定要做什么,这可能是不直观的,所以这实际上是一种折衷

在粗略的伪代码中,这些自定义函数之一如下

def _hybrid_lower(value):
   if isinstance(value, F):  # maybe F would be sufficient or some other class higher in the hierarchy
       # https://docs.djangoproject.com/en/2.2/ref/models/expressions/#func-expressions
       return Func(value, function='LOWER')
   else:
       return value.lower()

然后可以在属性和queryset都调用的函数中使用这个自定义函数。如果您确实开始需要非常复杂的函数,例如数据库操作和Python,那么代码的一些重复可能不是最糟糕的权衡。

谢谢,这是一个非常有趣的答案。我不确定是否使用第一个解决方案,因为它只抽象乘法,而不是整个业务逻辑。我的意思是,即使使用
乘法
函数,我仍然能够将
历史价格
历史价格
中的错误字段相乘。
def _hybrid_lower(value):
   if isinstance(value, F):  # maybe F would be sufficient or some other class higher in the hierarchy
       # https://docs.djangoproject.com/en/2.2/ref/models/expressions/#func-expressions
       return Func(value, function='LOWER')
   else:
       return value.lower()