Django:将一个模型对象的整个集合转换为单个字典

63

如果您是从谷歌搜索模型转字典来到这里的,请跳过我的问题,直接跳到第一个答案。我的问题只会让您更加困惑。

Django中是否有一种好的方法可以将模型的整个对象集转换为单个字典?我的意思是像这样:

class DictModel(models.Model):
    key = models.CharField(20)
    value = models.CharField(200)


DictModel.objects.all().to_dict()

...生成一个由Model中的记录组成的键/值对字典?有其他人发现这对他们有用吗?

谢谢。

更新
我只是想补充一点,我的最终目标是能够在模板中进行简单的变量查找。类似于:

{{ DictModel.exampleKey }}

通过 DictModel.objects.get(key__exact=exampleKey).value 的结果。

总的来说,你们非常让我惊喜,你们的回答帮了我很多,而且解决问题的方式也各不相同。非常感谢你们。

更新于2011年10月: 如果你在谷歌上搜索 "django model_to_dict",这个问题会成为搜索结果中排名最高的,这真是糟糕透了,因为它解决的问题与我的问题完全不同。

我的需求是将查询集中所有实例映射到一个字典中,并以指定模型字段作为键。
而 model_to_dict 则是将单个模型实例转换为字典。

现在,当时我有非常特别的需求,可能非常罕见(我甚至无法记起需要它的项目或原因)。因此,我会非常惊讶如果有人正在寻找关于 model_to_dict 的信息时,会发现我的问题实际上有用。抱歉。

model_to_dict 的使用情况似乎比我想象中要普遍得多。

更新于2011年12月:
我更改了标题,希望能更好地反映我的初衷。


1
如果您正在寻找如何将单个django模型转换为字典,请转到此处:https://dev59.com/fmEh5IYBdhLWcg3w3muK - Zags
1
list_of_json = [model_to_dict(model) for model in list_of_models] - FreshPow
这是唯一一个完全回答了OP确切问题的答案。 - Jakub Holan
12个回答

217

你也可以依赖于已经编写好的Django代码 ;).

from django.forms.models import model_to_dict
model_to_dict(instance, fields=[], exclude=[])

12
这个解决方案很不错,但我注意到有一个问题。由于这种方法是为表单使用而编写的,它无法转储具有“editable=False”标志的字段。 - Lukasz Korzybski
1
可以补充说明的是,这似乎无法获取父模型的字段。 - Izz ad-Din Ruhulessin
37
model_to_dict(instance, fields=[field.name for field in instance._meta.fields]) - Filip Dupanović
6
考虑到这个回答的好评,我觉得有必要指出model_to_dict提供的与我最初询问的东西根本不同。model_to_dict可以将单个模型实例转换为字典,这非常好。我想要的是能够将查询集中的所有实例映射到一个单一的字典中,并以指定的模型字段作为键。 - LarrikJ
9
从你的问题中,我并不能推断出那正是你想要的。此外,使用 model_to_dict 可以让你达到你所说的最终目标。别忘了,你的问题标题是“将整个模型转换为单个字典”。 - Herman Schaaf
4
model_to_dict(instance, fields=[field.name for field in instance._meta.fields]) 不会导出被标记为 editable=False 的字段。可以使用以下代码代替:{field.name: field.value_from_object(instance) for field in instance._meta.fields}。请注意,翻译时需要保持内容准确无误、简洁易懂,并且不得添加额外的解释性内容。 - Rockallite

26

您正在寻找QuerySet的Values成员,它允许您从查询中获取字典列表。

返回一个ValuesQuerySet--一个QuerySet,它会被评估为字典列表而不是模型实例对象。每个字典都代表一个对象,其中键对应于模型对象的属性名称。

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

我认为他不想要一个字典列表,而是想要一个单一的字典,其中键是模型键。 - Anurag Uniyal
.values() 不会返回像 ImageField() 等字段的值。 - Janaka R Rajapaksha

19

这是否需要创建一个实际的字典?你是否可以只使用外观上类似于字典的东西?

class DictModelAdaptor():
    def __init__(self, model):
        self.model = model

    def __getitem__(self, key):
        return self.model.objects.get(key=key)

    def __setitem__(self, key, item):
        pair = self.model()
        pair.key = key
        pair.value = item
        pair.save()

    def __contains__(self, key):
        ...

你可以用以下方式包装一个模型:

modelDict = DictModelAdaptor(DictModel)
modelDict["name"] = "Bob Jones"

etc...


如果这在模板变量查找中有效,那可能正是我想要的。你试过吗?我需要几个小时才能尝试。 - LarrikJ
是的,我在许多情况下使用了容器适配器,尽管我肯定不想以这种方式使用整个模型。另请注意,此示例有些简略。您需要添加一些额外的处理程序和适当的错误处理。 - SingleNegationElimination
我选择了这个答案,因为它最适合我的具体情况(比我描述的情况稍微复杂一些)。其他回答也很好,同样有效。我最喜欢的部分是逐个查找,而不是一次性加载整个表格。直到我看到它,我甚至没有意识到我想要这个功能。 - LarrikJ

17
您需要使用查询集方法in_bulk,根据文档说明:

接受一个由字段值(id_list)和这些值对应的field_name组成的列表,并返回一个字典,将每个值映射到具有给定字段值的对象实例。如果未提供id_list,则返回查询集中的所有对象。 field_name必须是唯一的字段,默认为主键。

它需要一个ID列表,因此您需要首先通过values_list方法获取它:
ids = MyModel.objects.values_list('id', flat=True)
ids_to_model_instances = MyModel.objects.in_bulk(ids)
# {1: <MyModel: 1>, 2: <MyModel: 2>, 3: <MyModel: 3>}

虽然在这个情况下这并没有帮到我,但这真的很不错,而且我以前不知道。谢谢! - LarrikJ
Django允许您拥有非整数的主键。如果您的模型以这种方式正确设置,这仍然可能是一个不错的解决方案。 - SingleNegationElimination
我正在做完全相同的事情。我已经得到了ID,但我想在一个数组中获取这些ID的数据。请帮帮我。 - numerah

14
你可以使用 python 序列化器
from django.core import serializers
data = serializers.serialize('python', DictModel.objects.all())

我还没有尝试过Django的序列化器,所以我很难弄清楚这该怎么做。我想我需要在交互式会话中尝试这个想法。虽然看起来可能是一个解决方案,但还是谢谢。 - LarrikJ
1
Django的serializers可以对queryset进行序列化,而model_to_dict只能对模型实例进行序列化。 - yegle

8

使用

dict(((m.key, m.value) for m in DictModel.objects.all())

根据Tom Leys的建议,我们不需要获取整个对象,只需获取我们需要的值,例如:

dict(((m['key'], m['value']) for m in DictModel.objects.values('key', 'value')))

如果需要所有值,最好将整个对象保存在字典中,例如:

dict(((m.key, m) for m in DictModel.objects.all())

1
我们应该将解决方案结合起来 - dict(((m['key'], m['value']) for m in DictModel.objects.all().values()) - 这样隐藏的id字段就不会从数据库中返回。 - Tom Leys
你好,你的回答是唯一一个回答了OP确切问题(也是我的问题)。 - Jakub Holan

6

dict((x.name, getattr(o, x.name)) for x in o._meta.fields)

这行代码创建了一个字典,从模型实例o中获取所有字段的名称和它们的值,并将它们存储在字典中。在这个字典中,每个字段名都是键,对应的值是模型实例o中该字段的值。

这个解决方案与Luper的serialize('python', ...)的区别之一在于,外键字段将被表示为实际相关对象。使用serialize,您只会得到相关对象的id值,而不是对象本身。 - Lukasz Korzybski

4
也许我理解有误,但是Django对象有一个__dict__属性,看起来这正是你需要的。

好像在这里找不到。它说[我的模型对象]没有属性'dict'。 - Rafael Almeida
我认为@ben的意思是__dict__ - Nav

2
user = mymodel.objects.all()
user.values() 

您还可以尝试:
user.values_list() # getting as list

2

要把模型的值转换为字典,可以在需要该字典的地方添加以下代码:

from models import DictModel

activity_map = dict(Plan.objects.values_list('key', 'value'))

activity_map是一个包含所需信息的字典。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接