Babayega
Babayega

Reputation: 33

How do I upload multiple images using django rest framework?

I am learning how to use djangorestframework by building a microblog and I want users to be able to upload multiple (kind of like how twitter works). I got a particular error(check below) after using a particular approach(check code).

I have attached my models.py, serializers.py and views.py file:

MODELS.PY FILE:
class TweetFile(models.Model):
    tweep =  models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    file = models.FileField(upload_to='images')

class Tweets(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    texts = models.TextField()
    file_content = models.ManyToManyField(TweetFile, related_name='file_content')
    date_posted = models.DateTimeField(auto_now_add=True)
    tweep = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    likes = models.PositiveIntegerField(default=0)
    liker = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='user_like')
    # link = models.URLField()

    class Meta:
        # verbose_name = _('my thing')
        verbose_name_plural = _('Tweets')

    def __str__(self):
        return f"{self.texts}"



SERIALIZERS.PY FILE:
class TweetSerializer(serializers.ModelSerializer):
    tweep = serializers.SerializerMethodField('get_tweep_username')
    likes = serializers.SerializerMethodField('get_tweet_likes')
    liker = serializers.StringRelatedField(many=True)

    class Meta:
        model = Tweets
        fields = ['id','texts', 'file_content', 'date_posted', 'tweep', 'likes', 'liker']
        extra_kwargs = {
            "file_content": {
                "required": False,
            }
        }


VIEWS.PY FILE: 
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def create_tweet(request):
    user = request.user
    if request.method == 'POST':
        serializer = TweetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(tweep=user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    else:
        return Response(serializer.errors, status=status.HTTP_405_METHOD_NOT_ALLOWED)

This particular approach gave me this error in my postman:

{ "file_content": [ "Incorrect type. Expected pk value, received InMemoryUploadedFile." ] }.

Could anybody tell me what I am doing wrong? or what I need to do? any help will be appreciated, thanks.

Upvotes: 1

Views: 172

Answers (1)

Babayega
Babayega

Reputation: 33

Okay, so I found a solution to this issue....and this is the code, hopefully someone finds it helpful:

models.py file

 class TweetFile(models.Model):
 tweep =  models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
 media = models.FileField(upload_to='images')

 def __str__(self):
     return f"{self.tweep.username}'s media images"


class Tweets(models.Model):
 id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
 texts = models.TextField()
 file_content = models.ManyToManyField(TweetFile, related_name='file_content', blank=True, null=True)
 date_posted = models.DateTimeField(auto_now_add=True)
 tweep = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

 class Meta:

     verbose_name_plural = _('Tweets')

 def __str__(self):
     return f"{self.texts}"

Serializer.py file

 from rest_framework import serializers
from tweets.models import Tweets, TweetFile, Comments


class TweetSerializer(serializers.ModelSerializer):
 tweep = serializers.SerializerMethodField('get_tweep_username')
 
 class Meta:
     model = Tweets
     fields = ['id','texts', 'file_content', 'date_posted', 'tweep']
     extra_kwargs = {
         "file_content": {
             "required": False,
         }
     }
     

  # function that returns the owner of a tweet
 def get_tweep_username(self, tweets):
     tweep = tweets.tweep.username
     return tweep

Views.py file

@api_view(['POST'])
@permission_classes([IsAuthenticated])
@parser_classes([MultiPartParser, FormParser])
def create_tweet(request):
 user = request.user
 if request.method == 'POST':
     files = request.FILES.getlist('file_content')
     if files:
         request.data.pop('file_content')
         serializer = TweetSerializer(data=request.data)
         if serializer.is_valid():
             serializer.save(tweep=user)
             tweet_qs = Tweets.objects.get(id=serializer.data['id'])
             uploaded_files = []
             for file in files:
                 content = TweetFile.objects.create(tweep=user, media=file)
                 uploaded_files.append(content)
             
             tweet_qs.file_content.add(*uploaded_files)
             context = serializer.data
             context["file_content"] = [file.id for file in uploaded_files]
             return Response(context, status=status.HTTP_201_CREATED)
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
     else:
         serializer = TweetSerializer(data=request.data)
         if serializer.is_valid():
             serializer.save(tweep=user)
             context = serializer.data
             return Response(context, status=status.HTTP_201_CREATED)
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 else:
     return Response(serializer.errors, status=status.HTTP_405_METHOD_NOT_ALLOWED)



configure your urls.py files appropriately and test the endpoint on POSTMAN, everything should work fine.

Upvotes: 1

Related Questions