如何使用相关的管理器和反向查找来清理这个Django查询集

时间:2015-09-06 05:39:49

标签: python django django-queryset

我有一些工作代码,但最近了解了相关管理器和反向查找,并想知道如何将它们应用于此代码:

我想使用相关管理器/反向查找的hacky方法是get_by_type_for_user(self, user)

class BadgeAssertionQuerySet(models.query.QuerySet):
    def get_user(self, user):
        return self.filter(user = user)

    def get_type(self, badge_type):
        return self.filter(badge__badge_type = badge_type)

    ...

class BadgeAssertionManager(models.Manager):
    def get_queryset(self):
    return BadgeAssertionQuerySet(self.model, using=self._db)

    ...

    def get_by_type_for_user(self, user):

        types = BadgeType.objects.all()
        qs = self.get_queryset().get_user(user)
        by_type =  [
                     {
                        'badge_type': t,
                        'list': qs.get_type(t)
                     } for t in types
                   ]

        return by_type

其中:

class BadgeAssertion(models.Model):
    badge = models.ForeignKey(Badge)
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    ...
    objects = BadgeAssertionManager()

class Badge(models.Model):
    name = models.CharField(max_length=50, unique=True)
    badge_type = models.ForeignKey(BadgeType)
    ....

class BadgeType(models.Model):
    name = models.CharField(max_length=50, unique=True)
    ...

我使用它的目的是为特定用户输出他们获得的徽章,按徽章类型排列:

来自视图:

context['badge_assertions_by_type'] = BadgeAssertion.objects.get_by_type_for_user(profile_user)
来自模板的

片段(这是用户的个人资料页面):

    {% for badges in badge_assertions_by_type %}
        {{badges.badge_type.name}}    
          {% for assertion in badges.list %}
              {{assertion.badge.name}}
              {{assertion.time_issued}}
          {% endfor %}
      {% endfor %}

1 个答案:

答案 0 :(得分:1)

您可以像这样简化您的方法:

def get_badges_by_type_for_user(self, user):        
    qs = self.get_queryset()
             .select_related('badge', 'badge__badge_type')
             .filter(user=user)
    badges = defaultdict(list)
    for badge_assertion in qs:
        badges[badge_assertion.badge.badge_type].append(badge_assertion.badge)
    return badges

您不需要迭代所有可用的BadgeType,而只需将您获得的断言分组到徽章类型的存储桶中。因此,不需要在badge_type上进行过滤。请注意此处使用defaultdict()。你可以尝试一下,看看它是否有效。 Haven自己测试了它。

现在结果结构不同了。它' S:

{
    badge_type1: [badge1, badge2, ...],
    badge_type2: [badge3, badge4, ...]
}

而不是:

[
    {'badge_type' : badge_type1, 'list': [badge1, badge2]},
    {'badge_type' : badge_type2, 'list': [badge3, badge4]}
]

第一个在这里更有意义。