【问题标题】:Django values() method with ManyToMany field: it just returns one element带有 ManyToMany 字段的 Django values() 方法:它只返回一个元素
【发布时间】:2016-03-29 16:14:27
【问题描述】:

我需要有效地将大量数据从我的数据库导出到 CSV,但我遇到了 ManyToMany 字段的问题。假设我的模型是Song,我正在使用一个名为Tags 的ManyToMany 字段。一个Song 可能有几个Tags,比如'rock'、'pop'、'sad'...

我想做这样的事情:

>>> 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') 之间有什么区别。

【问题讨论】:

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


【解决方案1】:

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

[{'id': 1L, 'tags': 'rock, pop, happy']}, {'id': 2L, 'tags': '金属、愤怒、史诗']}, . ..]

原始 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

【讨论】:

  • 谢谢!不幸的是,我们的数据库不在 Postgress 上,而是在 MySQL 中,并且 string_agg() 不可用。但我喜欢使用原始 SQL 查询的想法,我会朝着这个方向前进。
猜你喜欢
  • 2020-02-18
  • 2012-06-22
  • 1970-01-01
  • 1970-01-01
  • 2021-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
相关资源
最近更新 更多