在我的Django代码中,对于OrderedArticle
对象,我需要计算一个hist_price
,它是两个字段的乘积:hist_unit_price
*quantity
。你知道吗
我做这件事的第一个方法是一个简单的属性:
class OrderedArticle(Model):
@property
def hist_price(self):
return self.hist_unit_price * self.quantity
然后,我意识到当我需要对这些价格进行大量计算时,出于性能原因,我不能使用这个属性,而是必须在数据库级别计算hist_price
。这就是为什么我为此编写了一个自定义查询集:
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
属性和_hist_price
查询集。你知道吗
问题
这很管用,但我很恼火写两次相同的业务逻辑。我有种感觉我在这里做得不对。 我认为我应该在代码级别确保,无论我使用属性还是queryset,它总是返回相同的结果。 在这个特定的例子中,业务逻辑是两个小数之间的简单乘法,所以应该可以,但是我的代码中还有其他更复杂的情况。你知道吗
你有办法改进我的代码吗?谢谢。你知道吗
这个想法类似于"hybrid attributes" from SQLAlchemy,它一直是asked about before——我对来自线程链的任何答案都不太满意(比如将这个计算值存储在表上的一个额外字段中,并且总是确保它保持更新)。你知道吗
只要所需的运算符重载为接受实际值或
F()
对象(例如基本数学运算符),您的属性和ExpressionWrapper函数都可以使用一些内部函数。你知道吗如果在其中一个混合函数中,它比基本的数字操作更复杂,并且您希望避免重复的业务逻辑,那么您需要编写一个包装函数,它可以使用python函数为属性调用者解析到正确的输出,以及可以为查询集调用者操作F对象以保持运算符重载的函数。但这将导致代码内省参数,以确定要做什么,这可能是不直观的,所以这是一种权衡。你知道吗
在粗糙的伪代码中,其中一个自定义函数如下
然后可以在属性和queryset都调用的函数中使用这个自定义函数。如果您确实开始需要非常复杂的函数,例如数据库操作和Python,那么代码的一些重复可能不是最糟糕的权衡。你知道吗
相关问题 更多 >
编程相关推荐