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

时间:2011-11-17 15:20:39

标签: django django-models django-queryset

比方说,我有两个模型这个简单的应用程序 - TagSomeModel

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次。我只需要一次访问。

2 个答案:

答案 0 :(得分:1)

作为评论中提到的ArgsKwargs - 我编写了自己的代码,其中包含了列表:

>>> 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'])
... 

这段代码的输出正是我所需要的,它只打了一次数据库。但它不是很优雅,我不喜欢这段代码:)

顺便说一下。最好在查询中使用pkid.values('id', 'tags').values('pk', 'tags')

答案 1 :(得分:0)

如何在模型上返回所有标记列表的自定义方法

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])