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

Oon*_*nah 5 python django rest json 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') 
Run Code Online (Sandbox Code Playgroud)

我想这样,当用户访问GUI并尝试制作新书时,他们可以从选择字段中选择一种体裁,然后将其翻译成其ID。如果用户通过rest API访问,则他们还必须输入ID。

当数据库为空白时,我可以成功地将新书发布到服务器上,并使用choicefield选择下拉列表。但是,当数据库中有一个条目时,出现以下错误。当我用序列化程序替换choicefield时,这解决了。但是,然后剩下输入字段而不是选择字段。有谁知道我该怎么解决?

TypeError at /book/
<Genre: Genre object> is not JSON serializable
Run Code Online (Sandbox Code Playgroud)

Ane*_*pic 2

您需要查看 a) 期望ChoiceField收到什么选择以及 b)values_list()返回什么。

a)从文档中期望“有效值列表或元组列表ChoiceField 在这种情况下,有效值将是您的流派的主键 ID。(key, display_name)

b)根据没有参数的文档,返回 “模型中的所有字段,按照它们声明的顺序”。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))
Run Code Online (Sandbox Code Playgroud)

如果您的模型上有一个字段Genre可以作为一个很好的“显示名称”,那么您可以这样做:

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

然而,上述两个选项都存在一个问题,即一旦您导入包含资源的文件,查询集就会被评估。(因为它立即被 ChoiceField 转换为列表)。

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

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

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

所以你应该这样做:

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

如果您需要为关系字段上的选择自定义“显示名称”,您可以在此处查看文档。