Django / python查询集 - 将另一个“子”查询集作为项添加到每个列表对象?

时间:2012-07-07 10:38:38

标签: python django typeerror django-queryset

道歉,如果这个问题的答案是显而易见的 - 我对django / python&到目前为止,我一直无法在我的搜索中找到解决方案。

我有一个简单的查询集,例如

members = LibraryMembers.objects.all()

我可以这样做: -

for m in members:
  member_books = LibraryBorrows.objects.filter(member_id=m[u'id'])

我真正想要的是能够将结果序列化为json,所以它看起来像这样: -

{
  "members":
  [
    {
      "id" : "1",
      "name" : "Joe Bloggs"
      "books":
      [
        {
          "name" : "Five Go Exploring",
          "author" : "Enid Blyton",
        },
        {
          "name" : "Princess of Mars",
          "author" : "Edgar Rice Burroughs",
        },
      ]
    }
  ]
}

在我看来,最明显的尝试是: -

for m in members:
  m[u'books'] = LibraryBorrows.objects.filter(member_id=m[u'id'])

但是我得到TypeError:'LibraryBorrows'对象不支持项目分配

有没有办法实现我追求的目标?

2 个答案:

答案 0 :(得分:2)

模型实例确实不是决定性的。现在,如果你想要dicts而不是模型实例,那么Queryset.values()就是你的朋友 - 你得到一个只有必填字段的dicts列表,你可以避免从数据库中检索不需要的字段并构建完整模型的开销实例。

>> members = LibraryMember.objects.values("id", "name")
>> print members
[{"id" : 1, "name" : "Joe Bloggs"},]

然后你的代码看起来像:

members = LibraryMember.objects.values("id", "name")
for m in members: 
    m["books"] = LibraryBorrows.objects.filter(
      member_id=m['id']
      ).values("name", "author")

现在,您仍然需要为每个父行发出一个额外的数据库查询,这可能效率不高,具体取决于LibraryMember的数量。如果您有数百或更多的LibraryMember,更好的方法是在LibraryBorrow上查询,包括LibraryMember中的相关字段,然后根据LibraryMember id重新组合行,即:

from itertools import group_by

def filter_row(row):
    for name in ("librarymember__id", "librarymember__name"):
        del row[name]
    return row

members = []
rows = LibraryBorrow.objects.values(
    'name', 'author', 'librarymember__id', 'librarymember__name'
     ).order_by('librarymember__id')


for key, group in group_by(rows, lambda r: r['librarymember__id']):
    group = list(group)     
    member = {
      'id' : group[0]['librarymember_id'], 
      'name':group[0]['librarymember_name']
      'books' = [filter_row(row) for row in group] 
       }
    members.append(member)

注意:这可以被视为过早优化(如果您的数据库中只有几个LibraryMember),但是为一个查询交换数百个或更多查询以及一些后处理通常会对“现实生活中的“数据集。”

答案 1 :(得分:0)

m是一个LibraryMember对象,因此您无法将其视为字典。作为旁注:大多数人不会以复数形式命名模型,因为它们只是建模对象的类,而不是对象的集合。

一种可能的解决方案是使用两个对象所需的值制作一个字典列表,如下所示:

o = [ { "id": m.id, "name": m.name, "books": [{"name": b.name, "author": b.author} for b in m.libraryborrows_set.all()] } for m in LibraryMembers.objects.all()]

请注意,您可以使用related manager获取给定成员的图书。为了更清晰:

o = []
for m in LibraryMembers.objects.all():
   member_books = [{"name": b.name, "author": b.author} for b in m.libraryborrows_set.all()] 
   o.append( { "id": m.id, "name": m.name, "books": member_books } )  

修改

序列化所有字段:

members = []
for member in LibraryMembers.objects.all():
    member_details = {}
    for field in member._meta.get_all_field_names():
        member_details[field] = getattr(member, field)
    books = []
    for book in member.librayborrows_set.all():
        book_details = {}
        for field in book._meta.get_all_field_names():
            book_details[field] = getattr(book, field)
        books.append(book_details)
    member_details['books'] = books
    members.append(member_details)

我还发现了直到今天才听说过的DjangoFullSerializers:

http://code.google.com/p/wadofstuff/wiki/DjangoFullSerializers