3

如果这个问题的答案很明显,我深表歉意——我对 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' 对象不支持项目分配

有什么办法可以实现我所追求的吗?

4

2 回答 2

1

Wellm是一个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()]

请注意,您可以使用相关管理器来获取给定成员的书籍。为了更清楚:

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

于 2012-07-07T11:49:07.200 回答
1

模型实例确实不是字典。现在,如果您想要字典而不是模型实例,那么Queryset.values()您的朋友就是 - 您将获得一个仅包含必填字段的字典列表,并且您避免了从数据库中检索不需要的字段和构建完整的模型实例的开销。

>> 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 的话),但是为一个查询和一些后处理交易数百或更多查询通常会对“现实生活”产生真正的影响数据集。

于 2012-07-07T13:27:54.350 回答