#python-3.x #django #django-rest-framework #annotations #many-to-many
Вопрос:
У меня в коде есть модели, похожие на следующие:
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=' ')
Я хотел бы вернуть набор аннотированных 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()
и это работает просто отлично. Проблема, с которой я сталкиваюсь, заключается в том, что набор запросов, возвращаемый этой командой, дублирует list_entry
объект, если у него более одной subtype
аннотации.
Например, если проект под номером 1234 имеет два подтипа проекта, » 1A » и «3A», я получаю два list_entry
объекта: один с subtype
аннотацией » 1A «и отдельный list_entry
объект для того же проекта с subtype
аннотацией «3A».
Я хотел бы, чтобы для проекта 1234 был возвращен ОДИН объект subtype
с аннотацией «1A», «2A», который в конечном итоге будет сериализован в объект JSON.
Должен быть простой способ сделать это?
Ответ №1:
Хорошо, потратив на это буквально 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')) gt;gt;gt; q[2].my_subtype ['1A', '3A']