使用ManyToMany字段的Django values()方法:它只返回一个元素

时间:2016-03-29 16:14:28

标签: python django performance export many-to-many

我需要有效地将大量数据从我的数据库导出到CSV,而我遇到了ManyToMany字段的问题。假设我的模型是Song,我正在使用名为Tags的ManyToMany字段。 Song可能有多个Tags,例如'摇滚','流行','悲伤'......

我想做点什么:

>>> songs_tags = Song.objects.filter(artist_id=5).values('id', 'tags__name')

然后我想得到类似的东西:

>>> songs_tags
[{'id': 1L, 'tags__name':['rock', 'pop', 'happy']}, {'id': 2L, 'tags__name': ['metal', 'angry', 'epic']}, ...]

然而,我实际得到的是:

>>> songs_tags
[{'id': 1L, 'tags__name': 'rock'}, {'id': 2L, 'tags__name': 'metal'}, ...]

为什么?

我检查过这些元素确实有多个标记,但是values()只报告其中一个,而不是全部。

注意:

我尝试重复for song in Song.objects.filter(artist_id=5)并阅读每个song.tags.all()。但它是斯洛伐克......

我还尝试使用prefetch_related()https://docs.djangoproject.com/en/1.9/ref/models/querysets/#prefetch-related)。我所做的是迭代for song in Song.objects.filter(artist_id=5).prefetch_related('tags')并阅读每个song.tags.all(),但它也很慢。事实上,我没有发现迭代Song.objects.filter(artist_id=5)Song.objects.filter(artist_id=5).prefetch_related('tags')之间存在任何差异。

1 个答案:

答案 0 :(得分:1)

您可以使用a raw SQL query让Postgres获取标记并将它们连接成一个字符串以获得类似的内容

[{' id':1L,'标签':'摇滚,流行,快乐']},{' id&# 39;:2L,'标签'金属,愤怒,史诗']},...]

原始SQL选择看起来像这样

SELECT modulename_song.name AS name,
       string_agg(modulename_tag.name, ', ') AS tags 
FROM modulename_song_tag  
INNER JOIN modulename_song ON song_id=modulename_song.id
INNER JOIN modulename_tag ON tag_id=modulename_tag.id
WHERE song_id IN (
    SELECT id FROM modulename_song 
    WHERE artist_id=5 )
GROUP BY modulename_song.id;

假设您有Django模型构建的以下表格

  • 歌曲表:modulename_song
  • 标记表:modulename_tag
  • ManyToMany关系表:modulename_song_tag