Django экспорт модели в csv для ManyToManyField

У меня есть несколько таблиц, для которых я успешно создал экспорт в CSV, основанный на Моделях. Однако для одной из них, где я подсчитываю "лайки" для новостей (постов), у меня ничего не получается

Вот моя модель:

class News(models.Model):
    news_title = models.CharField(max_length=300)
    news_text = models.TextField(max_length=2000)
    news_author = models.CharField(max_length=150)
    news_date = models.DateField(default=now)
    likes = models.ManyToManyField(User, related_name='user_like', blank=True)

    @property
    def total_likes(self):
        return self.likes.count()

Проблема в том, что я могу вывести в CSV все элементы из модели, но если я вывожу "лайки", я получаю дублированные (или более) строки в CSV. Причина в том, что если новость понравилась 3 пользователям, я получаю 3x строки в CSV для каждого пользователя и в колонке "Like Count" я получаю их ID.

Что я хотел бы получить вместо этого: 1x строка для каждой новости с общим количеством лайков для каждой новости.

и view.py

@login_required
def export_news(request):
    newss = News.objects.all()
    response = HttpResponse(content_type='txt/csv')
    writer = csv.writer(response)
    writer.writerow(["ID","Title","Author","Date","Text","Likes Count"])
    
    for news in newss.values_list('id','news_title','news_author','news_date','news_text','likes'):
        writer.writerow(news)
        
    response['Content-Disposition'] = 'attachment; filename="News_list.csv"'

    return response

Благодарю за любую помощь. Thx

Вам нужно аннотировать подсчет лайков на кверисете newss и затем вызвать это агрегированное значение в values_list. Что-то вроде:

from django.db.models import Count

newss = News.objects.annotate(num_likes=Count('likes')).all()
...
for news in newss.values_list('id','news_title','news_author','news_date','news_text','num_likes'):
    writer.writerow(news)

Ваша проблема в том, что запрос values_list действительно вернет элемент списка для каждой совпадающей записи, как если бы вы сделали этот запрос на SQL. Поскольку вы возвращаете likes, который не является полем 1:1, вы можете ожидать, что в этом запросе будет более одной строки для каждой новости. Если вам нужен только свернутый агрегат, вам нужно указать это в запросе с помощью аннотации, а затем вернуть только аннотированное значение, а не полную запись likes из запроса.

Вернуться на верх