Reputation: 115
I am trying to be able to serialize and upload multiple images to associate with each post.
This is my 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)
my 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
my 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)
I am getting this error:
AttributeError: Got AttributeError when attempting to get a value for field image
on serializer PaintingSerializer
.
The serializer field might be named incorrectly and not match any attribute or key on the Painting
instance.
Original exception text was: 'Painting' object has no attribute 'image'.
I am also not sure if I should create another app just to handle all the images.
Thanks so much in advance!
Upvotes: 0
Views: 1048
Reputation: 115
Hey guys I ended up finding the answer. This stackoverflow answer explains it really well: Multiple images per Model where I messed up was not adding the related_name argument to my photo in my PaintingPhotos model.
Upvotes: 0
Reputation: 325
Your code looks similar enough to the docs here: https://www.django-rest-framework.org/api-guide/relations/#nested-relationships I can't see what exactly is wrong, but it could be that you haven't created a PaintingPhotos
object so there is no model to serialize it. I mentioned in a comment that you can create this through the Django admin.
Upvotes: 1