0

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!

6
  • Are you able to save the images to DB/storage backend using HTTP requests? Did you check the DB to ensure that? Commented Sep 17, 2019 at 5:10
  • @JPG I am using PostgreSQL do you think that's possible? What alternative would you suggest instead? Commented Sep 17, 2019 at 14:05
  • Files are uploaded to the file system and the path is stored in the DB. Check your MEDIA_ROOT setting. You also specified the folder 'uploaded_paintings', so the path will be whatever is in MEDIA_ROOT plus that. You can test if it is working by creating a PaintingPhotos object with an image in the Django admin. Commented Sep 17, 2019 at 20:18
  • 1
    You should also name the class PaintingPhoto if you want to stick to Django standards. Django will pluralize it where appropriate to display. It seems minor, but it will save you bugs from typing things inconsistently in the long run. Commented Sep 17, 2019 at 20:25
  • 1
    I think this is a valid answer to your problem : stackoverflow.com/questions/48756249/…. Commented Oct 4, 2019 at 12:01

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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.

2 Comments

That link doesn't work. I figured it was something to do with that though.
I think you may have meant to link here? stackoverflow.com/questions/537593/multiple-images-per-model I have updated this answer with the link (the previous one did not work)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.