我正在使用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。如果用户通过rest API访问,则他们还必须输入ID。
当数据库为空时,我可以成功地将新书发布到服务器上,并使用choicefield选择下拉列表。但是,当数据库中有一个条目时,出现以下错误。当我用序列化程序替换choicefield时,这解决了。但是,然后我剩下一个输入字段,而不是一个选择字段。有谁知道我该怎么解决?
TypeError at /book/
<Genre: Genre object> is not JSON serializable
最佳答案
您需要看一下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'))
但是上面的两个选项都存在一个问题,即导入包含资源的文件后,将立即对queryset进行评估。 (因为它会由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。