如何使用文件字段更新嵌套的序列化器

时间:2019-01-21 14:56:04

标签: python django django-rest-framework

我有2个模型:个人资料图片。与具有model.ForeignKey()构造的Image相关的配置文件字段“徽标”。我想通过更新请求(带有JSON有效负载的补丁)来更新我的个人资料记录。

我该怎么做?

我尝试发送此JSON

{
    "name": "TestName",
    "company": "myCompany",
    "phone": "33222111",
    "website": "site.com"
}

没关系,记录已更新。但!在图像模型中,我有models.ImageField()。我应该如何通过另一个序列化程序处理该字段?

然后我尝试发送此JSON(数据库中存在的Image记录的122 id)

REQUEST:
{
   "logo": 122
}

ANSWER:
{
    "logo": {
        "non_field_errors": [
            "Invalid data. Expected a dictionary, but got int."
        ]
    }
}

好,所以,我应该发送存在记录的对象

REQUEST:
{
   "logo": {
        "id": 122,
        "uuid": "bf9ba033-208f-47e0-86e5-93c44e05a616",
        "created": "2018-12-20T12:54:57.178910Z",
        "original_name": "hello.png",
        "filetype": "png",
        "file": "http://localhost/upload/img/0a9lg1apnebb.png",
        "owner": 1
   }
}

ANSWER:
{
    "logo": {
        "file": [
            "The submitted data was not a file. Check the encoding type on the form."
        ]
    }
}

这是我的两个模型和序列化器

class Image(models.Model):
    id = models.AutoField(primary_key=True)
    uuid = models.UUIDField(primary_key=False, default=uuid.uuid4, editable=False)
    created = models.DateTimeField(auto_now_add = True)
    original_name = models.CharField(max_length = 256, default=None)
    filetype = models.CharField(max_length = 10, default=None)
    file = models.ImageField(upload_to=update_img_filename,
                         default="static/noimg.jpg")
    owner = models.ForeignKey(User, related_name="images",
                          on_delete=models.CASCADE, null=True)


class Profile(models.Model):
    user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
    name = models.CharField(max_length=256, blank=True, null=True)
    company = models.CharField(max_length=256, blank=True, null=True)
    phone = models.CharField(max_length=256, blank=True, null=True)
    website = models.CharField(max_length=256, blank=True, null=True)
    logo = models.ForeignKey(Image, related_name="profile_logo",
                                on_delete=models.SET_NULL, null=True,
                                blank=True, default=None)
    is_admin = models.BooleanField(default=False)
    owner = models.ForeignKey(User, related_name="profiles",
                          on_delete=models.CASCADE, null=True)

class ProfileSerializer(serializers.ModelSerializer):
    logo = ImageSerializer()

    class Meta:
        model = Profile
        fields = '__all__'
        extra_kwargs = {
            'owner': {'read_only': True},
            'user': {'read_only': True},
            'is_admin': {'read_only': True},
        }

    def create(self, validated_data):
        return Profile.objects.create(**validated_data)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

class ImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Image
        fields = '__all__'
        extra_kwargs = {
            'owner': {'read_only': True}
        }

    def validate(self, data):
        extension = str(data['file']).split(".")[-1].lower()
        original_name = str(data['file'])

        if 'original_name' not in data:
            data['original_name'] = original_name
        if 'filetype' not in data:
            data['filetype'] = extension

        return data

    def create(self, validated_data):
        return Image.objects.create(**validated_data)

2 个答案:

答案 0 :(得分:0)

在数据库中,模型Profile与模型logo_id具有Image映射。 如果您想与现有徽标建立联系,请尝试使用json

{
    "name": "TestName",
    "company": "myCompany",
    "phone": "33222111",
    "website": "site.com",
    "logo: 122
}




class ProfileSerializer(serializers.ModelSerializer):
    logo = ImageSerializer()

    class Meta:
        model = Profile
        fields = '__all__'
        extra_kwargs = {
            'owner': {'read_only': True},
            'user': {'read_only': True},
            'is_admin': {'read_only': True},
        }
    def create(self, validated_data):
        logo_id = validated_data.pop('logo')
        profile = Profile.objects.create(**validated_data)
        logo_instance = Image.objects.get(pk=logo_id)
        profile.logo = logo_instance
        profile.save()

    def update(self, instance, validated_data):
        nested_serializer = self.fields['logo']
        nested_instance = instance.profile
        nested_data = validated_data.pop('logo')
        nested_serializer.update(nested_instance, nested_data)
        return super(ProfileSerializer, self).update(instance, validated_data)

答案 1 :(得分:0)

如果仅需要从现有图像中设置图像,则可以执行以下操作:

class ProfileSerializer(serializers.ModelSerializer):
    logo = ImageSerializer()

    class Meta:
        model = Profile
        fields = '__all__'
        extra_kwargs = {
            'owner': {'read_only': True},
            'user': {'read_only': True},
            'is_admin': {'read_only': True},
        }

class ImageSerializer(serializers.ModelSerializer):

    def to_internal_value(self, data):
        return Image.objects.get(pk=data)

    class Meta:
        model = Image
        fields = '__all__'
        extra_kwargs = {
            'owner': {'read_only': True}
        }
...

然后您将可以发送json:

{
    "name": "TestName",
    "company": "myCompany",
    "phone": "33222111",
    "website": "site.com"
    "logo": 122
}

将设置图像。