将类变量名传递给类方法

时间:2018-02-14 10:27:04

标签: python django django-models

我的模型定义如下:

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_formatedis_this_doneis_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方法。这当然不是一种干嘛的做事方式。

我只想要一个方法,我可以传递参数传递给过滤方法。

您可以帮助或提供提示,以便以干燥方式获得相同的结果吗?

2 个答案:

答案 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})
相关问题