使用跨多对多关系的 'related_name' 注释 Django 查询集(否 'Count'、'Avg'、'Max'、...)
Annotate a Django Queryset Using a 'related_name' Across a ManyToMany Relationship (NO 'Count', 'Avg', 'Max', ...)
我的代码中有类似于以下的模型:
class CompanyProject(models.Model):
""" This class holds project related information read in from the 'project'
custom 'manage.py' command.
"""
project_number = models.IntegerField(blank=False, null=False, unique=True)
project_worktype = models.CharField(blank=True, max_length=255, null=True)
created_at = models.DateTimeField(auto_now_add=True, blank=False, null=False)
updated_at = models.DateTimeField(auto_now=True, blank=False, null=False)
last_seen = models.DateField(blank=False, null=False)
def get_project_subtypes(self):
subtypes = self.project_subtype.all()
return [ subtype.project_subtype for subtype in subtypes ]
class Meta:
ordering = ['project_number']
class CompanySubType(models.Model):
class CompanySubTypeChoices(models.TextChoices):
G1A = '1A', _('1A')
G1B = '1B', _('1B')
G2A = '2A', _('2A')
G2B = '2B', _('2B')
G3A = '3A', _('3A')
G3B = '3B', _('3B')
company_project = models.ManyToManyField(CompanyProject, related_name='project_subtype')
project_subtype = models.CharField(blank=False, choices=CompanySubTypeChoices.choices, max_length=2, null=False)
class ListEntry(models.Model):
list_project = models.OneToOneField(CompanyProject, on_delete=models.CASCADE, related_name='list_project')
list_reviewer = models.ForeignKey('auth.User', on_delete=models.CASCADE, related_name='+')
我想要 return 一组带注释的 ListEntry
对象,这些对象用 ListEntry
项目标识的所有项目子类型的列表进行注释。
最终,我需要能够将这个带注释的数据传递给 Django REST Framework 序列化程序,但我首先需要让注释像我希望的那样工作。
我的问题是我可以很好地注释做这样的事情:
list_entry_qs = ListEntry.objects.prefetch_related('list_project', 'list_reviewer').annotate(subtypes=F('list_pmatt__project_subtype__project_subtype')).all()
而且效果很好。我遇到的问题是,从该命令 return 编辑的查询集会复制 list_entry
对象,如果它有多个 subtype
注释。
例如,如果编号为 1234 的项目有两个项目子类型“1A”和“3A”,我得到两个 list_entry
对象:一个带有 subtype
注释“1A”和一个单独的list_entry
同一项目的对象,带有 subtype
注释“3A”。
我想要一个针对项目 1234 的单个对象 returned,它有一个 subtype
注释“1A”、“2A”,最终将被序列化为一个 JSON 对象.
必须有一个简单的方法来做到这一点吗?
好的,在这上面花了 8 个小时后,我终于找到了如何做:
from django.contrib.postgres.aggregates.general import ArrayAgg
q = ListEntry.objects.prefetch_related('list_pmatt', 'list_reviewer', 'list_pmatt__project_subtype').annotate(my_subtype=ArrayAgg('list_pmatt__project_subtype__project_subtype'))
>>> q[2].my_subtype
['1A', '3A']
我的代码中有类似于以下的模型:
class CompanyProject(models.Model):
""" This class holds project related information read in from the 'project'
custom 'manage.py' command.
"""
project_number = models.IntegerField(blank=False, null=False, unique=True)
project_worktype = models.CharField(blank=True, max_length=255, null=True)
created_at = models.DateTimeField(auto_now_add=True, blank=False, null=False)
updated_at = models.DateTimeField(auto_now=True, blank=False, null=False)
last_seen = models.DateField(blank=False, null=False)
def get_project_subtypes(self):
subtypes = self.project_subtype.all()
return [ subtype.project_subtype for subtype in subtypes ]
class Meta:
ordering = ['project_number']
class CompanySubType(models.Model):
class CompanySubTypeChoices(models.TextChoices):
G1A = '1A', _('1A')
G1B = '1B', _('1B')
G2A = '2A', _('2A')
G2B = '2B', _('2B')
G3A = '3A', _('3A')
G3B = '3B', _('3B')
company_project = models.ManyToManyField(CompanyProject, related_name='project_subtype')
project_subtype = models.CharField(blank=False, choices=CompanySubTypeChoices.choices, max_length=2, null=False)
class ListEntry(models.Model):
list_project = models.OneToOneField(CompanyProject, on_delete=models.CASCADE, related_name='list_project')
list_reviewer = models.ForeignKey('auth.User', on_delete=models.CASCADE, related_name='+')
我想要 return 一组带注释的 ListEntry
对象,这些对象用 ListEntry
项目标识的所有项目子类型的列表进行注释。
最终,我需要能够将这个带注释的数据传递给 Django REST Framework 序列化程序,但我首先需要让注释像我希望的那样工作。
我的问题是我可以很好地注释做这样的事情:
list_entry_qs = ListEntry.objects.prefetch_related('list_project', 'list_reviewer').annotate(subtypes=F('list_pmatt__project_subtype__project_subtype')).all()
而且效果很好。我遇到的问题是,从该命令 return 编辑的查询集会复制 list_entry
对象,如果它有多个 subtype
注释。
例如,如果编号为 1234 的项目有两个项目子类型“1A”和“3A”,我得到两个 list_entry
对象:一个带有 subtype
注释“1A”和一个单独的list_entry
同一项目的对象,带有 subtype
注释“3A”。
我想要一个针对项目 1234 的单个对象 returned,它有一个 subtype
注释“1A”、“2A”,最终将被序列化为一个 JSON 对象.
必须有一个简单的方法来做到这一点吗?
好的,在这上面花了 8 个小时后,我终于找到了如何做:
from django.contrib.postgres.aggregates.general import ArrayAgg
q = ListEntry.objects.prefetch_related('list_pmatt', 'list_reviewer', 'list_pmatt__project_subtype').annotate(my_subtype=ArrayAgg('list_pmatt__project_subtype__project_subtype'))
>>> q[2].my_subtype
['1A', '3A']