serializers.py
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = [
'popularity',
'director',
'genre',
'imdb_score',
'name',
]
views.py
class MovieList(generics.ListCreateAPIView):
queryset = Movie.objects.all().order_by('-id')[:10]
serializer_class = MovieSerializer
permission_classes = (IsAuthenticated,)
def list(self, request):
queryset = self.get_queryset()
serializer = MovieSerializer(queryset, many=True)
return Response(serializer.data)
def post(self, request, format=None):
data = request.data
if isinstance(data, list):
serializer = self.get_serializer(data=request.data, many=True)
else:
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
我像这样发送我的数据,它工作正常。
{
"popularity": 83.0,
"director": "Victor Fleming",
"genre": [
1,
2,
3,
4
],
"imdb_score": 8.3,
"name": "The Wizard of Oz"
}
但我想发送的数据有点像这样:
{
"popularity": 83.0,
"director": "Victor Fleming",
"genre": [
"Adventure",
"Family",
"Fantasy",
"Musical"
],
"imdb_score": 8.3,
"name": "The Wizard of Oz"
}
查看类型列表-我发送的是name
,而不是主键。
这些是我的模特:
class Genre(models.Model):
name = models.CharField(max_length=30, unique=True) # make unique
def __str__(self):
return self.name
class Movie(models.Model):
popularity = models.FloatField(max_length=10)
director = models.CharField(max_length=30)
genre = models.ManyToManyField(Genre)
imdb_score = models.FloatField(max_length=10)
name = models.CharField(max_length=30)
即使当我列出数据或获取数据时,它也应该发送流派名称而不是ID。我尝试使用StringRelatedField
,但它给了我错误。
必须实现/API/movie/ www.example.com上的未实现错误StringRelatedField.to_内部值()。
7条答案
按热度按时间zpf6vheq1#
假设您在
MovieSerializer
中使用StringRelatedField
,如下所示:当检索电影列表时,结果将如下所示:
但是如果你想创建一个新的电影,那么它就不会工作,因为
StringRelatedField
是只读的。但是,您可以创建自定义相关字段。
这是完整的**
serializers.py
**:这是一个简单的示例,可以通过多种方式进行高度定制。
方法
display_value
定义了对象类型是如何显示的,例如在表单中,这里它只返回对象类型,即__str__
的输出。方法
to_representation
定义了对象Genre在输出中的显示方式(JSON或XML)。它与前面的方法非常相似,但这里我们必须显式地将Genre转换为字符串。当然,您可以根据自己的要求创建更复杂的输出。方法
to_internal_value
通过获取给定值的对象Genre来解决实际问题,如果这里有更复杂的方法to_representation
,则需要扩展逻辑来获取适当的对象。使用这种方法,您可以按照所需的格式发布JSON,指定流派名称而不是它们的id。
我希望这个例子对其他人也有帮助。
rwqw0loc2#
重写序列化程序的**
create()
**方法,如下所示,rkkpypqq3#
一个解决方案是重写序列化器中的
genre
字段,以接受如下字符串列表:在validate方法中,尝试按名称获取每个对象,并放入一个新列表,然后用新的对象列表更新
data
结果(我知道这不是最干净的解决方案,但它工作得很好)您还可以尝试使用
MethodSerializer
或定义一个GenreSerializer
,并按名称获取其中的对象,然后在父序列化程序中将其用作输入。mrfwxfqh4#
简单的解决方案是将
Genre
模型更改为使用name
作为主键,如下所示:这在这里并不重要,但这也将在数据库中保存一列,因为自动生成的
id
列将消失:)在对这个答案的评论中进行了一些讨论之后,我发现提到使用ANY类型作为主键是很重要的,您还应该避免在以后更改该字段。
这是因为对主键的更改也需要更新指向该主键的所有外键,并且(从这个问题的Angular 来说)即使包含流派的表相对较小,也可能有大量的电影指向每个流派。
raogr8fs5#
如果你总是把name传递给你的序列化器,你可以在Model defination中添加外键字段。
blmhpbnm6#
使用
SerializerMethodField
,则无需修改您的模型。xzabzqsa7#
您可以使用序列化程序字段方法。这将保留模型上的PK声明,并且您可以排除ForeignKey的字段。
示例: