Django Rest Framework:将多个图像序列化为一个 post in
Django Rest Framework: Serialize multiple images to one post in
我正在尝试能够序列化并上传多张图片以关联每个 post。
这是我的models.py
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save
from .utils import unique_slug_generator
class Painting(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default="", on_delete=models.CASCADE)
title = models.CharField(blank=False, null=False, default="", max_length=255)
slug = models.SlugField(blank=True, null=True)
style = models.CharField(blank=True, null=True, default="", max_length=255) #need to figure out why there is problem when this is False
description = models.TextField(blank=True, null=True, default="")
size = models.CharField(blank=True, null=True, default="", max_length=255)
artist = models.CharField(blank=True, null=True, default="", max_length=255)
price = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=20)
available = models.BooleanField(default=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __str__(self):
return self.title
class Meta:
ordering = ["-timestamp", "-updated"]
class PaintingPhotos(models.Model):
title = models.ForeignKey(Painting, default="", on_delete=models.CASCADE)
image = models.ImageField(upload_to='uploaded_paintings')
def pre_save_painting_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(pre_save_painting_receiver, sender=Painting)
我的serializers.py
from django.contrib.auth import get_user_model, authenticate, login, logout
from django.db.models import Q
from django.urls import reverse
from django.utils import timezone
from rest_framework import serializers
from .models import Painting, PaintingPhotos
User = get_user_model()
class UserPublicSerializer(serializers.ModelSerializer):
username = serializers.CharField(required=False, allow_blank=True, read_only=True)
class Meta:
model = User
fields = [
'username',
'first_name',
'last_name',
]
# # add PaintingImagesSerializer with the images model here
class PaintingPhotosSerializer(serializers.ModelSerializer):
class Meta:
model = PaintingPhotos
fields =[
'image'
]
#becareful here, if anyone submits a POST with an empty title, it will result in the empty slug, (which will mess up the url lookup since the title is the slug in this case)
#make title a required field in the actual interface, also remember to don't submit s POST with an empty title from the Django restframework directly
class PaintingSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='paintings-api:detail',
read_only=True,
lookup_field='slug'
)
user = UserPublicSerializer(read_only=True)
owner = serializers.SerializerMethodField(read_only=True)
image = PaintingPhotosSerializer(many=True, read_only=False)
class Meta:
model = Painting
fields = [
'url',
'user',
'title',
'style',
'description',
'size',
'artist',
'price',
'available',
'updated',
'timestamp',
'owner',
'slug',
'image',
]
def get_owner(self, obj):
request = self.context['request']
if request.user.is_authenticated:
if obj.user == request.user:
return True
return False
我的views.py
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework import generics, permissions, pagination, status
from .models import Painting
from .permissions import IsOwnerOrReadOnly
from .serializers import PaintingSerializer
class PaintingPageNumberPagination(pagination.PageNumberPagination):
page_size = 5
page_size_query_param = 'size'
max_page_size = 20
def get_paginated_response(self, data):
author = False
user = self.request.user
if user.is_authenticated:
author = True
context = {
'next': self.get_next_link(),
'previous': self.get_previous_link(),
'count': self.page.paginator.count,
'author': author,
'results': data,
}
return Response(context)
class PaintingDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Painting.objects.all()
serializer_class = PaintingSerializer
lookup_field = 'slug'
permission_classes = [IsOwnerOrReadOnly]
class PaintingListCreateAPIView(generics.ListCreateAPIView):
queryset = Painting.objects.all()
serializer_class = PaintingSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
pagination_class = PaintingPageNumberPagination
def perform_create(self, serializer):
serializer.save(user=self.request.user)
我收到这个错误:
AttributeError:尝试在序列化程序 PaintingSerializer
上获取字段 image
的值时出现 AttributeError。
序列化程序字段的命名可能不正确,并且与 Painting
实例上的任何属性或键都不匹配。
原始异常文本为:'Painting' 对象没有属性 'image'.
我也不确定是否应该创建另一个应用程序来处理所有图像。
非常感谢!
您的代码看起来与此处的文档非常相似:https://www.django-rest-framework.org/api-guide/relations/#nested-relationships 我看不出到底出了什么问题,但可能是您还没有创建 PaintingPhotos
对象,所以有没有模型来序列化它。我在评论中提到您可以通过 Django 管理员创建它。
大家好,我终于找到了答案。这个 Whosebug 答案解释得很好:Multiple images per Model
我搞砸的地方是没有在我的 PaintingPhotos 模型中向我的照片添加 related_name 参数。
我正在尝试能够序列化并上传多张图片以关联每个 post。
这是我的models.py
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save
from .utils import unique_slug_generator
class Painting(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default="", on_delete=models.CASCADE)
title = models.CharField(blank=False, null=False, default="", max_length=255)
slug = models.SlugField(blank=True, null=True)
style = models.CharField(blank=True, null=True, default="", max_length=255) #need to figure out why there is problem when this is False
description = models.TextField(blank=True, null=True, default="")
size = models.CharField(blank=True, null=True, default="", max_length=255)
artist = models.CharField(blank=True, null=True, default="", max_length=255)
price = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=20)
available = models.BooleanField(default=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __str__(self):
return self.title
class Meta:
ordering = ["-timestamp", "-updated"]
class PaintingPhotos(models.Model):
title = models.ForeignKey(Painting, default="", on_delete=models.CASCADE)
image = models.ImageField(upload_to='uploaded_paintings')
def pre_save_painting_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(pre_save_painting_receiver, sender=Painting)
我的serializers.py
from django.contrib.auth import get_user_model, authenticate, login, logout
from django.db.models import Q
from django.urls import reverse
from django.utils import timezone
from rest_framework import serializers
from .models import Painting, PaintingPhotos
User = get_user_model()
class UserPublicSerializer(serializers.ModelSerializer):
username = serializers.CharField(required=False, allow_blank=True, read_only=True)
class Meta:
model = User
fields = [
'username',
'first_name',
'last_name',
]
# # add PaintingImagesSerializer with the images model here
class PaintingPhotosSerializer(serializers.ModelSerializer):
class Meta:
model = PaintingPhotos
fields =[
'image'
]
#becareful here, if anyone submits a POST with an empty title, it will result in the empty slug, (which will mess up the url lookup since the title is the slug in this case)
#make title a required field in the actual interface, also remember to don't submit s POST with an empty title from the Django restframework directly
class PaintingSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='paintings-api:detail',
read_only=True,
lookup_field='slug'
)
user = UserPublicSerializer(read_only=True)
owner = serializers.SerializerMethodField(read_only=True)
image = PaintingPhotosSerializer(many=True, read_only=False)
class Meta:
model = Painting
fields = [
'url',
'user',
'title',
'style',
'description',
'size',
'artist',
'price',
'available',
'updated',
'timestamp',
'owner',
'slug',
'image',
]
def get_owner(self, obj):
request = self.context['request']
if request.user.is_authenticated:
if obj.user == request.user:
return True
return False
我的views.py
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework import generics, permissions, pagination, status
from .models import Painting
from .permissions import IsOwnerOrReadOnly
from .serializers import PaintingSerializer
class PaintingPageNumberPagination(pagination.PageNumberPagination):
page_size = 5
page_size_query_param = 'size'
max_page_size = 20
def get_paginated_response(self, data):
author = False
user = self.request.user
if user.is_authenticated:
author = True
context = {
'next': self.get_next_link(),
'previous': self.get_previous_link(),
'count': self.page.paginator.count,
'author': author,
'results': data,
}
return Response(context)
class PaintingDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Painting.objects.all()
serializer_class = PaintingSerializer
lookup_field = 'slug'
permission_classes = [IsOwnerOrReadOnly]
class PaintingListCreateAPIView(generics.ListCreateAPIView):
queryset = Painting.objects.all()
serializer_class = PaintingSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
pagination_class = PaintingPageNumberPagination
def perform_create(self, serializer):
serializer.save(user=self.request.user)
我收到这个错误:
AttributeError:尝试在序列化程序 PaintingSerializer
上获取字段 image
的值时出现 AttributeError。
序列化程序字段的命名可能不正确,并且与 Painting
实例上的任何属性或键都不匹配。
原始异常文本为:'Painting' 对象没有属性 'image'.
我也不确定是否应该创建另一个应用程序来处理所有图像。
非常感谢!
您的代码看起来与此处的文档非常相似:https://www.django-rest-framework.org/api-guide/relations/#nested-relationships 我看不出到底出了什么问题,但可能是您还没有创建 PaintingPhotos
对象,所以有没有模型来序列化它。我在评论中提到您可以通过 Django 管理员创建它。
大家好,我终于找到了答案。这个 Whosebug 答案解释得很好:Multiple images per Model 我搞砸的地方是没有在我的 PaintingPhotos 模型中向我的照片添加 related_name 参数。