如何在 post 请求中正确保存嵌套对象?
How to save a nested object in a post request correctly?
我正在尝试处理 post 请求,我首先要保存一个 Tag 对象,然后它会成为 Tagging 对象的标签字段。但是,无论我尝试过什么组合,尽管 Tag Post 方法有效,当我传递一个 json 对象时,如下所示:
{
"user_id": 1,
"gameround_id": 2015594866,
"resource_id": 2975,
"tag": {
"name": "TESTTAGGGG2222",
"language": "en"
},
"score": 0,
"origin": ""
}
我不断收到这条消息:
{
"name": [
"This field is required."
],
"language": [
"This field is required."
]
}
但是,当我传递标签时,它起作用了。
这是post方法:
def post(self, request, *args, **kwargs):
if not isinstance(request.user, CustomUser):
current_user_id = 1
else:
current_user_id = request.user.pk
gameround = request.data.get('gameround', '')
random_resource = request.data.get('resource', '')
created = datetime.now()
score = 0
origin = ''
name = request.data.get('name', '')
language = request.data.get('language', '')
tag_serializer = TagSerializer(data=request.data)
tagging_serializer = TaggingSerializer(data=request.data)
if tag_serializer.is_valid(raise_exception=True):
tag_serializer.save(tag=request.data)
if tagging_serializer.is_valid(raise_exception=True):
tagging_serializer.save(tagging=request.data, tag=tag_serializer.data)
return Response({"status": "success", "data": tagging_serializer.data},
status=status.HTTP_201_CREATED)
# else:
# return Response({"status": "success", "data": tag_serializer.data},status=status.HTTP_201_CREATED)
else:
return Response({"status": "error", "data": tag_serializer.errors},
status=status.HTTP_400_BAD_REQUEST)
如何在 post 方法中正确传递嵌套对象,以便不再出现此错误?
models.py
class Tag(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
return self.name or ''
@property
def tags(self):
tags = self.tagging.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language')
class Tagging(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, related_name='taggings')
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, related_name='taggings')
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name='tagging')
created = models.DateTimeField(editable=False, null=True)
score = models.PositiveIntegerField(default=0)
# media_type = models.ForeignKey(Gamemode, on_delete=models.CASCADE)
origin = models.URLField(max_length=256, blank=True, default='')
objects = models.Manager()
def __str__(self):
return str(self.tag) or ''
serializers.py
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('name', 'language')
def create(self, validated_data):
tag_data = validated_data.pop('tag')
Tag.objects.create(**tag_data)
return tag_data
def to_representation(self, data):
data = super().to_representation(data)
return data
class TaggingSerializer(serializers.ModelSerializer):
tag = TagSerializer(required=False, write_only=False)
resource_id = serializers.PrimaryKeyRelatedField(queryset=Resource.objects.all(),
required=True,
source='resource',
write_only=False)
gameround_id = serializers.PrimaryKeyRelatedField(queryset=Gameround.objects.all(),
required=False,
source='gameround',
write_only=False)
user_id = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all(),
required=False,
source='user',
write_only=False)
class Meta:
model = Tagging
fields = ('id', 'user_id', 'gameround_id', 'resource_id', 'tag', 'created', 'score', 'origin')
depth = 1
def create(self, validated_data):
"""Create and return a new tagging"""
tag_data = validated_data.pop('tag', None)
if tag_data:
tag = Tag.objects.get_or_create(**tag_data)[0]
validated_data['tag'] = tag
tagging = Tagging(
user=validated_data.get("user"),
gameround=validated_data.get("gameround"),
resource=validated_data.get("resource"),
tag=validated_data.get("tag"),
created=datetime.now(),
score=validated_data.get("score"),
origin=validated_data.get("origin")
)
tagging.save()
return tagging
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['tag'] = TagSerializer(instance.tag).data
return rep
在您的 post 方法中,您制作了
tag_serializer = TagSerializer(data=request.data)
if tag_serializer.is_valid(raise_exception=True):
# the rest of the code
这意味着您的数据将传递给 TagSerializer
因此 DRF 将检查此序列化程序的字段是否在请求正文中,并且未提供,因为此数据不属于此序列化程序, 它属于 TaggingSerializer
所以这会给你一个错误 This field is required
因此,您只需要将请求数据发送到 TaggingSerializer
,尝试一下,让我们看看会发生什么,我建议使用 serializers.Serializer
而不是使用 serializers.ModelSerializer
更好的表现
我正在尝试处理 post 请求,我首先要保存一个 Tag 对象,然后它会成为 Tagging 对象的标签字段。但是,无论我尝试过什么组合,尽管 Tag Post 方法有效,当我传递一个 json 对象时,如下所示:
{
"user_id": 1,
"gameround_id": 2015594866,
"resource_id": 2975,
"tag": {
"name": "TESTTAGGGG2222",
"language": "en"
},
"score": 0,
"origin": ""
}
我不断收到这条消息:
{
"name": [
"This field is required."
],
"language": [
"This field is required."
]
}
但是,当我传递标签时,它起作用了。
这是post方法:
def post(self, request, *args, **kwargs):
if not isinstance(request.user, CustomUser):
current_user_id = 1
else:
current_user_id = request.user.pk
gameround = request.data.get('gameround', '')
random_resource = request.data.get('resource', '')
created = datetime.now()
score = 0
origin = ''
name = request.data.get('name', '')
language = request.data.get('language', '')
tag_serializer = TagSerializer(data=request.data)
tagging_serializer = TaggingSerializer(data=request.data)
if tag_serializer.is_valid(raise_exception=True):
tag_serializer.save(tag=request.data)
if tagging_serializer.is_valid(raise_exception=True):
tagging_serializer.save(tagging=request.data, tag=tag_serializer.data)
return Response({"status": "success", "data": tagging_serializer.data},
status=status.HTTP_201_CREATED)
# else:
# return Response({"status": "success", "data": tag_serializer.data},status=status.HTTP_201_CREATED)
else:
return Response({"status": "error", "data": tag_serializer.errors},
status=status.HTTP_400_BAD_REQUEST)
如何在 post 方法中正确传递嵌套对象,以便不再出现此错误?
models.py
class Tag(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
return self.name or ''
@property
def tags(self):
tags = self.tagging.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language')
class Tagging(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, related_name='taggings')
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, related_name='taggings')
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name='tagging')
created = models.DateTimeField(editable=False, null=True)
score = models.PositiveIntegerField(default=0)
# media_type = models.ForeignKey(Gamemode, on_delete=models.CASCADE)
origin = models.URLField(max_length=256, blank=True, default='')
objects = models.Manager()
def __str__(self):
return str(self.tag) or ''
serializers.py
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('name', 'language')
def create(self, validated_data):
tag_data = validated_data.pop('tag')
Tag.objects.create(**tag_data)
return tag_data
def to_representation(self, data):
data = super().to_representation(data)
return data
class TaggingSerializer(serializers.ModelSerializer):
tag = TagSerializer(required=False, write_only=False)
resource_id = serializers.PrimaryKeyRelatedField(queryset=Resource.objects.all(),
required=True,
source='resource',
write_only=False)
gameround_id = serializers.PrimaryKeyRelatedField(queryset=Gameround.objects.all(),
required=False,
source='gameround',
write_only=False)
user_id = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all(),
required=False,
source='user',
write_only=False)
class Meta:
model = Tagging
fields = ('id', 'user_id', 'gameround_id', 'resource_id', 'tag', 'created', 'score', 'origin')
depth = 1
def create(self, validated_data):
"""Create and return a new tagging"""
tag_data = validated_data.pop('tag', None)
if tag_data:
tag = Tag.objects.get_or_create(**tag_data)[0]
validated_data['tag'] = tag
tagging = Tagging(
user=validated_data.get("user"),
gameround=validated_data.get("gameround"),
resource=validated_data.get("resource"),
tag=validated_data.get("tag"),
created=datetime.now(),
score=validated_data.get("score"),
origin=validated_data.get("origin")
)
tagging.save()
return tagging
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['tag'] = TagSerializer(instance.tag).data
return rep
在您的 post 方法中,您制作了
tag_serializer = TagSerializer(data=request.data)
if tag_serializer.is_valid(raise_exception=True):
# the rest of the code
这意味着您的数据将传递给 TagSerializer
因此 DRF 将检查此序列化程序的字段是否在请求正文中,并且未提供,因为此数据不属于此序列化程序, 它属于 TaggingSerializer
所以这会给你一个错误 This field is required
因此,您只需要将请求数据发送到 TaggingSerializer
,尝试一下,让我们看看会发生什么,我建议使用 serializers.Serializer
而不是使用 serializers.ModelSerializer
更好的表现