使用ChoiceField时,类型错误对象不是JSON可序列化的

时间:2016-03-20 14:39:41

标签: python json django rest django-rest-framework

我使用Django Rest框架在Django中创建REST API,不能使用任何其他库或插件。过去几天我遇到了一个问题,我无法解决问题。

在我的seralizer.py中,我有以下内容

class BookSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source = 'owner.username')
    genres = serializers.ChoiceField(choices=Genre.objects.values_list())
    # genres = GenreSerializer()

class Meta:
    model = VideoGame
    fields = ('title', 'description', 'brief', 'genres', 'owner') 

我希望当用户访问GUI并尝试制作新书时,他们可以从一个选择字段中选择一个类型,然后将其转换为其ID。如果用户通过其余API访问,则他们还必须输入ID。

当数据库为空时,我能够成功将新书发布到服务器并使用choicefield选择下拉列表。但是当数据库有一个条目时,我会得到以下错误。当我用序列化器替换choicefield时,这就解决了。然而,我留下了输入字段而不是选择字段。有谁知道我怎么解决这个问题?

TypeError at /book/
<Genre: Genre object> is not JSON serializable

2 个答案:

答案 0 :(得分:2)

您需要查看a)ChoiceField期望作为选择接收的内容以及b)values_list()返回的内容。

a)来自the docs ChoiceField期望“有效值列表或(key, display_name)元组列表。”在这种情况下,有效值会成为你的类型的主要键ID。

b)根据the docs values_list()没有参数返回“模型中的所有字段,按照它们被声明的顺序。”

我认为您可能无法使用choices=Genre.objects.values_list()收到问题中显示的错误消息...也许您尝试了choices=Genre.objects.all()

无论如何,你可以这样做:

class BookSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source = 'owner.username')
    genres = serializers.ChoiceField(choices=Genre.objects.values_list('pk', flat=True))

如果您的Genre型号上有一个可以显示良好'显示名称'的字段,那么您可以这样做:

class BookSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source = 'owner.username')
    genres = serializers.ChoiceField(choices=Genre.objects.values_list('pk', 'name'))

但是上面的两个选项都存在一个问题,即导入包含资源的文件后,将立即对进行评估。(因为它由ChoiceField立即转换为列表。

在导入时有这样的副作用是不好的做法。此外,由于每次启动服务器时只评估过一次,因此当您更改类型时,选项将会过时。

幸运的是有更好的选择:
http://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield

这类似于Django中的ModelChoiceField。它有一个queryset参数,用于验证选择......但与ChoiceField不同,它知道不立即评估查询集。每次需要验证选项时都会对其进行评估。

所以你应该这样做:

class BookSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source = 'owner.username')
    genres = serializers.PrimaryKeyRelatedField(queryset=Genre.objects.all())

如果您需要为关系字段中的选项自定义“显示名称”,则可以看到the docs here

答案 1 :(得分:0)

当模型已更改但未迁移时,我通常会收到此类错误。 尝试这样做。这可能会有所帮助