【问题标题】:Django rest framework - multiple image uploads not showingDjango rest框架 - 多个图像上传不显示
【发布时间】:2020-07-30 22:54:58
【问题描述】:

我想通过这个answer 在 Post 模型中上传多张图片。

作为管理员,我可以成功地将多张图片上传到证书字段,但是当我在浏览器中查看帖子详细信息或帖子列表页面时,证书不显示。

这是json:

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1,
            "title": "Post One",
            "description": "Lorem ipsum",
            "url": "http://www.postone.com",
            "country": "United Kingdom",
            "coverImage": "http://localhost:8000/media/cover_images/Post%20One/earth-large_yPJZXAH.jpg",
            "tags": [
                "UK"
            ],
            "creator": "Admin",
            "slug": "post-one"
        }
    ]
}

由于某种原因,在管理员中上传的证书图像未显示在帖子详细信息或列表页面上。

以下是模型:

class Post(models.Model):
    creator = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='posts')
    title = models.CharField(_('Title'), max_length=255, blank=False, null=False)
    description = models.TextField(_('Description'), max_length=500, blank=False, null=False)
    url = models.URLField(_('URL'), unique=True, max_length=255, blank=False, null=False)
    country = models.CharField(_('Country'), max_length=255, blank=False, null=False)
    cover_image = ProcessedImageField(
        verbose_name=_('Cover'),
        blank=False,
        null=False,
        format='JPEG',
        options={'quality': 90},
        processors=[ResizeToFill(600, 200)],
        upload_to=cover_image_directory)

    STATUS_DRAFT = 'D'
    STATUS_PUBLISHED = 'P'
    STATUSES = (
        (STATUS_DRAFT, 'Draft'),
        (STATUS_PUBLISHED, 'Published'),
    )
    status = models.CharField(blank=False, null=False, choices=STATUSES, default=STATUS_DRAFT, max_length=2)
    tags = TaggableManager(blank=True)
    slug = models.SlugField(max_length=255, unique=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


    def save(self, *args, **kwargs):
        if self.slug:  # edit
            if slugify(self.title) != self.slug:
                self.slug = generate_unique_slug(Post, self.title)
        else:  # create
            self.slug = generate_unique_slug(Post, self.title)
        super(Post, self).save(*args, **kwargs)

    def get_tags(self):
        """ names() is a django-taggit method, returning a ValuesListQuerySet
        (basically just an iterable) containing the name of each tag as a string
        """
        return self.tags.names()

    def __str__(self):
        """Return post title"""
        return self.title

    def get_absolute_url(self):
        return reverse('posts:detail', kwargs={'slug': self.slug})

    def is_draft(self):
        return self.status == STATUS_DRAFT
    class Meta:
        ordering = ['-created_at',]


class PostCertificateImage(models.Model):
    post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
    image = ProcessedImageField(
        verbose_name=_('Certificate'),
        blank=True,
        null=True,
        format='JPEG',
        options={'quality': 90},
        processors=[ResizeToFill(100, 100)],
        upload_to=certificate_directory)

    def __str__(self):
        return self.post.title

序列化器:

class PostCertificateImageSerializer(serializers.ModelSerializer):

    class Meta:
        model = PostCertificateImage
        fields = ('image',)


class PostSerializer(serializers.ModelSerializer):
    tags = TagSerializer(source='get_tags')
    creator = CreatorField(queryset=User.objects.all())
    certificate_images = PostCertificateImageSerializer(many=True, read_only=True)

    class Meta:
        model = Post
        fields = (
            'id',
            'title',
            'description',
            'url',
            'country',
            'certificate_images',
            'cover_image',
            'tags',
            'creator',
            'slug',
        )

还有观点:

class PostList(generics.ListAPIView):
    queryset = Post.objects.filter(status='P').order_by('-created_at')
    serializer_class = PostSerializer
    permission_classes = (permissions.AllowAny,)

    def get_queryset(self, *args, **kwargs):
        queryset = Post.objects.filter(status='P').order_by('-created_at')
        return queryset


class PostDetail(generics.RetrieveAPIView):
    queryset = Post.objects.filter(status='P')
    serializer_class = PostSerializer
    permission_classes = (permissions.AllowAny,)

我知道这个question 的答案并没有那么老。代码似乎运行良好,但我看不到证书图像。

【问题讨论】:

    标签: django serialization view django-rest-framework


    【解决方案1】:

    如果您没有为序列化器字段指定 source 参数,它会尝试使用同名属性 (reference) 中的数据。这里的问题是certificate_images 序列化器字段尝试使用名为certificate_images 的属性,但没有找到它(Post 模型没有名为certificate_images 的属性)。

    要克服这个问题,您有两种选择:

    1. certificate_images 序列化器字段设置正确的source,或者
    2. PostCertificateImage 模型的post 字段设置自定义related_name

    让我们从第一个选项开始。 post 字段的默认 related_namepostcertificateimage_set (reference)。要将其用作源,您需要将source='postcertificateimage_set' 添加到序列化器字段参数中,因此序列化器字段将使用与反序列化对象相关的PostCertificateImage 对象:

    class PostSerializer(serializers.ModelSerializer):
        # ...
        certificate_images = PostCertificateImageSerializer(many=True, read_only=True, source='postcertificateimage_set')
    

    第二个选项是在PostCertificateImage 模型的ForeignKey 字段上设置自定义related_name。这样,序列化器字段将能够找到certificate_images 属性。但是,这样做有一个缺点:您最终会得到一个新的数据库迁移 (reference)。这是代码,如果您使用此选项:

    class PostCertificateImage(models.Model):
        post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE, related_name='certificate_images')
        # ...
    

    【讨论】:

    • 感谢您的回答。选项 1 看起来最简单,但它不起作用。但是,选项 2 奏效了。再次感谢
    • @MaxRah 对不起,我忘记在选项 #1 的代码中添加 source='postcertificateimage_set' 参数。现在修好了。我在本地测试过,效果很好。干杯!
    猜你喜欢
    • 2021-02-19
    • 2018-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-02
    • 2018-10-31
    • 2019-09-18
    • 2018-07-13
    相关资源
    最近更新 更多