我使用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
答案 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)
当模型已更改但未迁移时,我通常会收到此类错误。 尝试这样做。这可能会有所帮助