我有一个非常复杂的模型
ALLOWED_STATES = {1,2,3}
class X(models.Model):
a = models.BooleanField()
b = models.ForeignKey('Y', on_delete=model.CASCADE)
c = models.IntegerField()
d = models.IntegerField()
@property
def can_delete(self)
# this goes on for 6 and clause
return self.a and self.b.c and self.c in ALLOWED_STATES and self.d != 5 and ..
我在annotate()调用和filter()中也需要这个属性
#in one endpoint
qs = X.objects.filter(...).annoate(can_delete=ExpressionWrapper(Q(a=True, b__c=True, c__in=ALLOWED_STATES,...) & ~Q(d=5), output_field=models.BooleanField())
我想知道是否有一种方法可以将同一属性的这些形式统一为一个,而无需在获取行后在python中调用can_delete。这两个表单已经成为一个维护性问题,因为PM一直在更改can_delete的定义。
2条答案
按热度按时间gv8xihay1#
如果在计算
can_delete()
时使用Q对象会怎么样?例如,将
can_delete()
更改为:警告:未经测试的代码。
这样做的代价是,现在每次调用
can_delete()
都需要调用一次数据库,即使内存中有对象。然而,由于您已经有了一种使用annotate为整个查询集计算this的方法,因此您每次只会为单个对象调用this,这并不坏。这样做的好处是,您可以在两个地方使用相同的Q表达式。
m1m5dgzv2#
您可以检查对象的属性内的can_delete注解:
如果前面的查询已经获得了信息,这将避免不必要的DB调用。
但是要注意,当您引用
obj.can_delete
时,引起注解的信息可能已经在DB中更改了。如果这是可能的,并且删除数据库中现在评估为can_delete_qs = False
的内容的后果是严重的,那么您不应该缓存此信息,而是每次都使用数据库查询重新评估它。为了维护性而不是效率,请删除Python评估,并使用Nico奥德尔的建议替换其余属性。此外,在一个地方(DRY)定义Q对象,并将其导入到任何需要的地方
我不知道的是,你是否可以在Django完全初始化数据库之前定义一个Q表达式。如果没有,你需要一个动态导入或一个惰性评估来延迟评估,直到Django启动并运行之后。