Django查询—;如何获取具有M2M关系的词典列表?

Django查询—;如何获取具有M2M关系的词典列表?,django,django-models,django-queryset,Django,Django Models,Django Queryset,比方说,我有一个简单的应用程序,它有两个模型-Tag和SomeModel class Tag(models.Model): text = ... class SomeModel(models.Model): tags = models.ManyToManyField(Tag, related_name='tags') 我想从数据库中得到如下信息: [{'id': 1, 'tags': [1, 4, 8, 10]}, {'id': 6, 'tags': []}, {'id': 8, '

比方说,我有一个简单的应用程序,它有两个模型-
Tag
SomeModel

class Tag(models.Model):
  text = ...

class SomeModel(models.Model):
  tags = models.ManyToManyField(Tag, related_name='tags')
我想从数据库中得到如下信息:

[{'id': 1, 'tags': [1, 4, 8, 10]}, {'id': 6, 'tags': []}, {'id': 8, 'tags': [1, 2]}]
它是几个SomeModel字典的列表,其中包含SomeModel的id和标记的id

Django查询应该是什么样子?我试过这个:

>>> SomeModel.objects.values('id', 'tags').filter(pk__in=[1,6,8])
[{'id': 1, 'tags': 1}, {'id': 1, 'tags': 4}, {'id': 1, 'tags': 8}, ...]
这不是我想要的,所以我试过这样的方法:

>>> SomeModel.objects.values_list('id', 'tags').filter(pk__in=[1,6,8])
[(1, 1), (1, 4), (1, 8), ...]
我最后一次尝试是:

>>> SomeModel.objects.values_list('id', 'tags', flat=True).filter(pk__in=[1,6,8])
...
TypeError: 'flat' is not valid when values_list is called with more than one field.
-

也许Django做不到这一点,所以最类似于我想要的结果是:

[{'id': 1, 'tags': 1}, {'id': 1, 'tags': 4}, {'id': 1, 'tags': 8}, ...]
是否有任何Python内置方法可以将其转换为此

[{'id': 1, 'tags': [1, 4, 8, 10]}, {'id': 6, 'tags': []}, {'id': 8, 'tags': [1, 2]}]
-编辑:

如果我在
SomeModel
中编写方法:

class SomeModel(models.Model):
  tags = models.ManyToManyField(Tag, related_name='tags')

  def get_tag_ids(self):
    aid = []
    for a in self.answers.all():
      aid.append(a.id)
    return aid
然后打电话:

>>> sm = SomeModel.objects.only('id', 'tags').filter(pk__in=[1,6,8])
# Hit database
>>> for s in sm:
...   s.get_tag_ids()
...
>>> # Hit database 3 times.

这不起作用,因为它访问数据库4次。我只需要一次访问。

模型上的自定义方法返回所有标记的列表怎么样

class Tag(models.Model):
  text = ...

class SomeModel(models.Model):
  tags = models.ManyToManyField(Tag, related_name='tags')

  def all_tags(self):
    return self.tags.values_list('pk',flat=True)
然后

SomeModel.objects.values('id', 'all_tags').filter(pk__in=[1,6,8])

那么模型上返回所有标记列表的自定义方法呢

class Tag(models.Model):
  text = ...

class SomeModel(models.Model):
  tags = models.ManyToManyField(Tag, related_name='tags')

  def all_tags(self):
    return self.tags.values_list('pk',flat=True)
然后

SomeModel.objects.values('id', 'all_tags').filter(pk__in=[1,6,8])
如评论中所述,我编写了自己的代码,其中包含以下列表:

>>> sm = SomeModel.objects.values('id', 'tags').filter(pk__in=[1,6,8])
>>> a = {}
>>> for s in sm:
...   if s['id'] not in a:
...     a[s['id']] = [s['tags'],]
...   else:
...     a[s['id']].append(s['tags'])
... 
这段代码的输出正是我所需要的,它只命中数据库一次。但是它不是很优雅,我不喜欢这个代码:)

顺便问一下,在查询中最好使用
pk
还是
id
.values('id','tags')
.values('pk','tags')

如评论中所述-我编写自己的代码,其中包含以下列表:

>>> sm = SomeModel.objects.values('id', 'tags').filter(pk__in=[1,6,8])
>>> a = {}
>>> for s in sm:
...   if s['id'] not in a:
...     a[s['id']] = [s['tags'],]
...   else:
...     a[s['id']].append(s['tags'])
... 
这段代码的输出正是我所需要的,它只命中数据库一次。但是它不是很优雅,我不喜欢这个代码:)


顺便问一下,在查询中最好使用
pk
还是
id
.values('id','tags')
.values('pk','tags')

不确定这是否有帮助,但您是否看过或?如果您不一定要对标记进行编码,那么您可以从它们那里收集一些代码,了解它们如何处理标记。我知道django标记,而不是django taggit。谢谢,但这只是我的爱好,我想尽可能多地学习Django,因此,我不想使用任何第三方代码。您可以随时编写自己的classmethod或Manager,以所需的格式返回数据。我不知道如何通过查询来实现这一点,但您不能自己打包列表吗?@Brandon Maybe method
get_tag_ids()
在SomeModel中返回标签ID列表。不确定这是否有帮助,但您是否查看了或?如果您不一定要对标记进行编码,那么您可以从它们那里收集一些代码,了解它们如何处理标记。我知道django标记,而不是django taggit。谢谢,但这只是我的爱好,我想尽可能多地学习Django,因此,我不想使用任何第三方代码。您可以随时编写自己的classmethod或Manager,以所需的格式返回数据。我不知道如何通过查询来实现这一点,但您不能自己打包列表吗?@Brandon Maybe method
get_tag_ids()
在返回标签ID列表的SomeModel中。我喜欢这个解决方案,可惜这是不可能的。运行此代码时,异常
FieldError:无法将关键字'all_tags'解析到字段中。选项包括:id,提出标签。
。回答您关于“pk”与“id”的问题;'pk'是一种快捷方式,它指向标识字段的任何内容。如果出于某种原因您更改了db的id字段(或正在处理外部对象,但不知道其pk字段名称),“pk”将始终指向正确标识字段的任何内容,如“更好”我不知道,但我喜欢“pk”,因为它感觉更通用,我喜欢这个解决方案,可惜这是不可能的。运行此代码时,异常
FieldError:无法将关键字'all_tags'解析到字段中。选项包括:id,提出标签。
。回答您关于“pk”与“id”的问题;'“pk”是一种快捷方式,它可以指向任何身份字段,如果您出于某种原因更改了db的id字段(或正在处理外部对象,但不知道其pk字段名称),“pk”将始终指向任何正确的身份字段,至于“better”,我不知道,但我喜欢“pk”,因为它感觉更普通、更干燥