如何使用相关管理器和反向查找来清理此 Django 查询集
How to use a related manager and reverse lookups to clean up this Django queryset
我有一些工作代码,但最近了解了相关管理器和反向查找,想知道如何将它们应用于此代码:
我想使用相关 Manager/reverse 查找的 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 %}
您可以像这样简化您的方法:
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()
。你可以试试这个,看看它是否有效。自己没测试过。
现在这里的结果结构不同了。它是:
{
badge_type1: [badge1, badge2, ...],
badge_type2: [badge3, badge4, ...]
}
而不是:
[
{'badge_type' : badge_type1, 'list': [badge1, badge2]},
{'badge_type' : badge_type2, 'list': [badge3, badge4]}
]
第一个在这里更有意义。
我有一些工作代码,但最近了解了相关管理器和反向查找,想知道如何将它们应用于此代码:
我想使用相关 Manager/reverse 查找的 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 %}
您可以像这样简化您的方法:
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()
。你可以试试这个,看看它是否有效。自己没测试过。
现在这里的结果结构不同了。它是:
{
badge_type1: [badge1, badge2, ...],
badge_type2: [badge3, badge4, ...]
}
而不是:
[
{'badge_type' : badge_type1, 'list': [badge1, badge2]},
{'badge_type' : badge_type2, 'list': [badge3, badge4]}
]
第一个在这里更有意义。