# models.py
class Post(models.Model):
content = models.TextField(blank=True, default='')
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class PostImage(models.Model):
image = models.ImageField(upload_to=unique_upload)
post = models.ForeignKey(
Post, related_name='images', on_delete=models.CASCADE)
这是我为基本场景设置的模型,用户可以输入内容或上传图片作为帖子。
我想捆绑我的逻辑以处理使用content
或images
或两者都创建帖子。
我首先开始玩GenericViewSet
和CreateViewSet
,但是图像从未传递给我的序列化器。
# views.py
class CreatePostViewSet(generics.CreateAPIView /* viewsets.GenericViewSet */):
permission_classes = (IsAuthenticated,)
queryset = Post.objects.order_by('id')
serializer_class = CreatePostSerializer
def create(self, request, *args, **kwargs):
data = {}
print(request.data)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(created_by=request.user)
# post = serializer.instance
# print(post)
# for im in post.images.all():
# im.save(post=post)
# print(post.images.all())
return Response(data,
status=status.HTTP_201_CREATED,
headers=self.get_success_headers(serializer.data))
# serializers.py
class PostImageSerializer(serializers.ModelSerializer):
class Meta:
model = PostImage
fields = ('id', 'url', 'image', 'post',)
read_only_fields = ('post',)
depth = 1
class CreatePostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, required=False)
class Meta:
model = Post
fields = ('id', 'url', 'content', 'images',)
read_only_fields = ('created_by',)
depth = 1
def create(self, validated_data):
# validated_data['images'] is always []
print(validated_data)
raise
images
在传递给序列化程序时始终为[]
,但在request.data['images']
中确实以[<TemporaryUploadedFile: 1 - 5H5hHgY.png (image/png)>, ...
的形式存在
我希望使用ModelSerializer来帮助自动解析ImageField。
# CreatePostSerializer serializers breaks down to
CreatePostSerializer():
id = UUIDField(read_only=True)
url = HyperlinkedIdentityField(view_name='post-detail')
content = CharField(allow_blank=True, required=False, style={'base_template': 'textarea.html'})
images = PostImageSerializer(many=True, required=False):
id = UUIDField(read_only=True)
url = HyperlinkedIdentityField(view_name='postimage-detail')
image = ImageField(max_length=100)
post = NestedSerializer(read_only=True):
id = UUIDField(read_only=True)
content = CharField(allow_blank=True, required=False, style={'base_template': 'textarea.html'})
created_by = PrimaryKeyRelatedField(queryset=User.objects.all())
答案 0 :(得分:2)
它认为request.data['images']
将需要稍作更改,因为您的PostImageSerializer
期望有一个包含“图像”键的对象,而您正在传递TemporaryUploadedFile
的列表。
鉴于request.data['images']
,您可以在将数据传递给序列化程序之前在视图中执行以下操作:
images_list: List[TemporaryUploadedFile] = request.data.pop("images")
images = []
for image in images_list:
images.append({
"image": image,
})
request.data["images"] = images
因此,我们正在使用图像键将您的TemporaryUploadedFiles
列表转换为对象列表。
:edit:您是否不想在视图上转换数据以使其与序列化程序兼容?然后,您可以更改序列化程序以使其与数据兼容,这涉及到自定义create
和update
方法,我现在仅向您展示如何覆盖create
方法
class CreatePostSerializer(serializers.ModelSerializer):
images = serializers.ImageField(many=True)
class Meta:
model = Post
fields = ('id', 'url', 'content', 'images',)
read_only_fields = ('created_by',)
depth = 1
def create(self, validated_data):
images = validated_data.pop("images")
post = super().create(validated_data)
for image in images:
serializer = PostImageSerializer(data={"image": image, "post": post.pk}, context=self.context)
serializer.is_valid()
serializer.save()
return post
因此您不想覆盖请求中的数据,也不想自定义序列化器的create方法?更改序列化器使用validate
方法将初始数据转换为已验证数据的方式(我认为这适用于嵌套序列化器,但未经测试):
class CreatePostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, required=False)
class Meta:
model = Post
fields = ('id', 'url', 'content', 'images',)
read_only_fields = ('created_by',)
depth = 1
def validate(self, attrs):
images_list = attrs.pop("images")
images = []
for image in images_list:
images.append({
"image": image,
})
attrs["images"] = images
return attrs
答案 1 :(得分:0)
因此,我能够按照@ARJMP的建议使用它。
# views.py
class CreatePostViewSet(generics.CreateAPIView):
# authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
queryset = Post.objects.order_by('id')
serializer_class = CreatePostSerializer
def create(self, request, *args, **kwargs):
data = {}
print(request.data)
images = [{'image': i} for i in request.data.pop('images', [])]
serializer = self.get_serializer(
data={'content': request.data['content'], 'images': images})
serializer.is_valid(raise_exception=True)
post = serializer.save(created_by=request.user)
# self.perform_create(serializer)
data['post'] = serializer.data
return Response(data,
status=status.HTTP_201_CREATED,
headers=self.get_success_headers(serializer.data))
# serializers.py
class CreatePostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, required=False)
class Meta:
model = Post
fields = ('id', 'content', 'images',
'is_private', 'created_by',)
read_only_fields = ('view_count', 'created',)
depth = 1
def create(self, validated_data):
images = validated_data.pop('images', [])
p = Post.objects.create(**validated_data)
for im in images:
pi = PostImage.objects.create(image=im['image'], post=p)
return p
我的想法是,要使其正常工作,这似乎有些令人费解。我自己做了很多操作。我真的希望能够利用ModelSerializer
和CreateAPIView
完成的更多“神奇”工作。
有更好的方法吗?