我的模型定义如下:
class ProblemVerificationModel(CreateUpdateDateModel):
problem = models.ForeignKey(Problem, related_name="problem_survey")
verifier = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="verified_problem")
is_problem_properly_formated = ... # BooleanField
is_this_done = ... # BooleanField
is_that_done = ... # BooleanField
# other BooleanFields
上述模型就像我的应用程序中的投票系统一样。我需要计算每个属性的投票百分比,例如is_problem_properly_formated
,is_this_done
,is_that_done
等。我正在使用classmethod,如下所示:
@classmethod
def percentage_problem_properly_formated(cls, problem):
votes = cls.objects.filter(problem=problem)
total_votes = votes.count()
yes_votes = votes.filter(is_problem_properly_formated=True).count()
percentage_yes = (yes_votes / total_votes) * 100
return percentage_yes
@classmethod
def percentage_is_this_done(cls, problem):
votes = cls.objects.filter(problem=problem)
total_votes = votes.count()
yes_votes = votes.filter(is_this_done=True).count()
percentage_yes = (yes_votes / total_votes) * 100
return percentage_yes
现在对于每个属性,我使用类似的方法,差异是将参数传递给filter方法。这当然不是一种干嘛的做事方式。
我只想要一个方法,我可以传递参数传递给过滤方法。
您可以帮助或提供提示,以便以干燥方式获得相同的结果吗?
答案 0 :(得分:3)
首先,这些对模型进行查询的方法确实属于Manager,而不是模型本身。
其次,您可以使用字典扩展动态传递字段以进行过滤。
class ProblemVerificationManager(models.Manager):
def percentage(self, problem, filter_keyword):
votes = self.filter(problem=problem)
total_votes = votes.count()
yes_votes = votes.filter(**{filter_keyword: True}).count()
percentage_yes = (yes_votes / total_votes) * 100
return percentage_yes
class ProblemVerificationModel(CreateUpdateDateModel):
...
objects = ProblemVerificationManager()
现在您将其称为ProblemVerificationModel.objects.percentage(problem, 'is_problem_properly_formatted')
。
在Django 2.0+中,您可以使用聚合返回完整计数和单个数据库查询中匹配的百分比:
from django.db.models import Count, Q
class ProblemVerificationManager(models.Manager):
def percentage(self, problem, filter_keyword):
votes = self.filter(problem=problem).aggregate(
yes_votes=Count(1, filter=Q(**{filter_keyword: True}),
total_votes=Count(1)
)
percentage_yes = (votes['yes_votes'] / votes['total_votes']) * 100
return percentage_yes
答案 1 :(得分:1)
将过滤器参数作为dict传递,并使用**
语法将其解压缩:
@classmethod
def percentage_is_this_done(cls, problem, filters):
votes = cls.objects.filter(problem=problem)
total_votes = votes.count()
yes_votes = votes.filter(filters).count()
percentage_yes = (yes_votes / total_votes) * 100
return percentage_yes
调用此方法:
MyClass.percentage_is_this_done(problem, {'is_this_done': True})