Django query with manytomany as list
Я работаю с django (4.1) и у меня проблема с QuerySet.
models.py
class Publication(models.Model):
title = models.CharField(max_length=30)
class Meta:
ordering = ['title']
def __str__(self):
return self.title
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
class Meta:
ordering = ['headline']
def __str__(self):
return self.headline
python manage.py shell
>>> from many2many.models import Article, Publication
>>> qsA = Article.objects.values("id","headline","publications")
>>> qsP = Publication.objects.values("id","title")
>>> for a in qsA:
... print(a)
...
{'id': 1, 'headline': 'A', 'publications': 1}
{'id': 1, 'headline': 'A', 'publications': 2}
{'id': 2, 'headline': 'B', 'publications': 3}
{'id': 2, 'headline': 'B', 'publications': 4}
>>> for a in qsP:
... print(a)
...
{'id': 1, 'title': 'tA1'}
{'id': 2, 'title': 'tA2'}
{'id': 3, 'title': 'tB1'}
{'id': 4, 'title': 'tB2'}
>>>
Я хотел бы иметь QuerySet, который возвращает "заголовок" Статьи, и список "заголовков" Публикации. Что-то вроде
{'headline': 'A', 'list_publications': 'tA1 tA2'}
{'headline': 'B', 'list_publications': 'tB1 tB2'}
Вы можете определить related_name
, чтобы легко получить доступ к связанной модели через неявное отношение.
Если вы определите related_name="articles"
внутри вашего M2M поля publications
, вы сможете получить доступ к статьям, связанным с публикацией, вызвав my_publication.articles.all()
Чтобы вернуть названия, связанные с публикациями, вы можете сделать следующее:
Publication.objects.annotate(titles=___("articles__title"))
annotate()
позволяет добавить в набор запросов столбец, не относящийся к таблице (обычно связанный или вычисляемый).
titles
- имя этого дополнительного столбца.
___
- это имя функции агрегирования в данном случае (мы обсудим ее далее).
"articles"
- это ваш related_name
.
"title"
- это столбец связанной модели, по которому вы хотите агрегировать.
Приведенный выше код агрегирует связанные названия для каждой публикации.
Итак, какую функцию агрегации использовать? Вот документация
https://docs.djangoproject.com/en/4.1/topics/db/aggregation/.
Внутри ничего полезного для вашего вопроса нет, так что вам придется обратиться к функциям агрегации для конкретных БД.
Из того, что я знаю:
.
Если вы используете Postgres, есть ArrayAgg
, но это выведет ["t1", "t2"]
.
https://docs.djangoproject.com/en/4.1/ref/contrib/postgres/aggregates/.
Если вы используете MariaDB или MySQL, вы можете использовать GroupConcat.
https://django-mysql.readthedocs.io/en/latest/aggregates.html