过滤后如何将分配的属性保留给查询集对象?备择方案?
Posted
技术标签:
【中文标题】过滤后如何将分配的属性保留给查询集对象?备择方案?【英文标题】:How to keep assigned attributes to a queryset object after filtering? Alternatives? 【发布时间】:2019-09-04 23:13:18 【问题描述】:也许这是一个奇怪的答案,所以我会解释我为什么要这样做。
我有一个产品模型。我必须为他们每个人分配一些库存。
所以我在 Products 模型上有一个函数,它可以计算很多必要的东西,例如库存并返回一个 QuerySet。
由于我的数据库模型有点“复杂”,在这种情况下我不能使用注释。所以我决定手动执行这个数据库查询,然后,在查询中为每个产品分配手动设置库存属性。比如:
for product in queryset_products:
product.stock = some_stock_calc...
当我想使用 filters 这个 queryset_product 时,问题就来了。 执行以下操作后:
queryset_products = queryset_products.filter(...)
股票属性丢失
有什么解决办法吗?
【问题讨论】:
AFAIK,唯一的解决方案是Django QSannotate
function
我不认为你可以这样做。因为querysets are lazy。对象仅在访问时创建。也许@property
可以解决你的问题。
【参考方案1】:
查询集上的所有操作,如.filter()
,在枚举查询集之前都是象征性的。然后编译并执行 SQL 查询。在未过滤的大查询集上计算库存然后再次过滤运行它是无效的。您可以将过滤器拆分为与附加到查询集的股票无关的条件,然后将与股票相关的过滤器拆分为您在计算股票的同一 Python 循环中评估。
result = []
for product in queryset_products.filter(**simple filters):
product.stock = some_stock_calc...
if product.stock > 0 or not required_on_stock:
result append(product)
可能有库存的可能有效产品的缓存字段对于第一个简单过滤器非常有用。
也许库存计算并不比例如午夜的股票加上午夜以来的股票操作总和。然后可以通过注释中的Subquery
计算当前库存并一起过滤。它将通过一个 SQL 编译为一个带有连接到您的相关模型的主查询和一个相对简单的股票子查询。 (那将是另一个问题。)
【讨论】:
【参考方案2】:可以用不同的方式解决,你可以运行一个循环为
queryset_products = list(queryset_products.filter(...))
for product in queryset_products:
setattr(product, "stock") = some_stock_calc...
基本上,您需要从数据库中获取所有记录,因为查询是惰性的,它将丢失,因为除非结果已被缓存/存储,否则它将被重新评估。
【讨论】:
【参考方案3】:由于您不能使用annotate()
,如果您可以在Product
表中添加一个单独的列来存储stock
,您可以随时进行filter
查询。
也许有一个 celery
任务,它为每个 Product
执行所有计算并保存到新列。
否则,如果没有annotate
,您就不能在查询集中拥有stock
属性。
【讨论】:
以上是关于过滤后如何将分配的属性保留给查询集对象?备择方案?的主要内容,如果未能解决你的问题,请参考以下文章
如何将指针分配给函数中的新对象,而该对象在退出后不会消失[重复]