使用base64ImageField和嵌套序列化程序时,以POST方法返回URL

时间:2019-04-18 08:16:34

标签: python django django-rest-framework base64

首先,我是Django的新手,对于后端开发同样是新手,所以请放轻松。

我正在为移动应用程序设置一个后端,在该后端中,用户应该能够通过Http Request发布带有附加图像的广告。现在,它的工作方式应该像它应该的那样,用户发送一个包含所有必需信息的POST请求,并返回一个包含所有相关信息的响应,但图像为 null 除外。我知道图像已成功上传到服务器,但是我不知道如何将图像的URL返回到响应中。

以下是我的代码:

models.py

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE repub SYSTEM "C:\repub\Repub_V1.dtd">
<?xml-stylesheet href="C:\repub\repub.xsl" type="text/xsl"?>
<repub>
<head>
<title>xxx</title>
</head>
<body>
<sec>
<title>First Title</title>
<break name="1-1"/>
<pps>This is Sparta</pps>
<h1><page num="1"/>First Heading</h1>
<bl>This is another text</bl>
<fig><img src="images/img_1-1.jpg" alt=""/><fc>This is a caption</fc></fig>
<p>This is a sentence<br><p/></br> that will be broken down <br><p/></br>into separate paragraph tags.</p>
</break>
</sec>
</body>
</repub>

我的序列化器如下:

serializers.py

class Advert(models.Model):

    owner=models.ForeignKey(User, on_delete=models.CASCADE, related_name="adverts")
    book_title = models.CharField(max_length=250)
    price = models.PositiveSmallIntegerField()
    created_at = models.DateTimeField(default=now())

    def __str__(self):
        return self.book_title + ' - ' + self.contact_info


class AdvertImage(models.Model):
    advert = models.ForeignKey(Advert, on_delete=models.CASCADE, related_name="image", null=True)
    image = models.ImageField(upload_to = 'ad_images', null=True)

    def __str__(self):
        return self.image.name

这是我的观点:

views.py

from rest_framework import serializers
from .models import Advert, AdvertImage
from drf_extra_fields.fields import Base64ImageField
from django.contrib.auth.models import User

class AdvertPostSerializer(serializers.ModelSerializer):
    image =  Base64ImageField(max_length=None, use_url=True, required=False)

    class Meta:
        model = Advert
        fields = (
        'id',
        'price',
        'book_title',
        'image')

    def create(self, validated_data):
        try:
            image_data = validated_data.pop('image')
        except:
            image_data = None
        advert = Advert.objects.create(**validated_data)
        if image_data is not None:
            image = AdvertImage.objects.create(advert=advert, image=image_data)

        return advert

为说明会发生什么,这是一个POST请求:

class AdvertViewSet(viewsets.ModelViewSet):
    queryset = Advert.objects.all()
    permission_classes = (AllowAny,)

    def get_serializer_class(self):
        if self.action == 'create':
            return AdvertPostSerializer
        return AdvertSerializer

    @action(methods=['get'], detail=False)
    def newest(self,request):
        newest = self.get_queryset().order_by('created_at').last()
        serializer = self.get_serializer_class()(newest)
        return Response(serializer.data)

    def perform_create(self, serializer):
        return serializer.save(owner=self.request.user)

这是响应:

POST http://localhost:8000/post-advert/ 
"Authorization: Token 980436128332ce3" 
book_title=my book 
price=1000
image=data:image/png;base64,iVBORHJvZmlsZSB0e//+egAAAAASUVORK5CYII=

查看数据库并将第二个GET请求发送到另一个视图表明,所有内容均按应有的方式上载,外键和其他功能均应按应有的方式工作,只是我很难弄清楚如何发送返回图片的URL作为对成功POST的响应。

2 个答案:

答案 0 :(得分:0)

因为您的

中的get_queryset()方法
 newest = self.get_queryset().order_by('created_at').last()

返回广告模型对象:

class AdvertViewSet(viewsets.ModelViewSet):
    queryset = Advert.objects.all()

没有图像字段。然后,您将创建 AdvertPostSerializer 对象,并使用最新查询集对其进行初始化,该查询集是 Advert 模型的查询集,而没有您的图片

serializer = self.get_serializer_class()(newest)

您可以通过某种方式在 @最新动作中获取 AdvertImage 对象,并尝试将其添加到响应中,但是认为您只能创建一个模型广告 >,其中包含您的 image 字段和一个序列化程序,您将在其中定义 Base64ImageField

答案 1 :(得分:0)

好的,所以我设法提出了一个(hacky?)解决方案。

在serializers.py中,我将Base64Field设置为read_only = True:

class AdvertPostSerializer(serializers.ModelSerializer):
    image =  Base64ImageField(max_length=None, use_url=True, required=False, read_only=True)
    ...

然后,在我的AdvertViewSet的views.py中,我这样覆盖了create()方法:

def create(self, request, format='json'):
        serializer = PostAdvertSerializer(data=request.data)
        if serializer.is_valid():
            advert = serializer.save()
            if advert:
                json = serializer.data
                advertImageURL = AdvertImage.objects.get(advert=advert).image.url
                json['img_link'] = request.build_absolute_uri(advertImageURL)
                return Response(json, status=status.HTTP_201_CREATED)

这将返回我图像的完整路径!