Home > Software engineering >  Django - POST endpoint to update multiple tables. Return response with all relevant data
Django - POST endpoint to update multiple tables. Return response with all relevant data

Time:10-18

I have this POST endpoint below that creates a post. When a post is created the request can be accompanied by video and images. As you can see below a serializer handles the post data outside of images and video, because I need to do validation on the image and video. The response returns the data serialized, but only everything not related to image and video. I'd like the response to also return stuff like image and video url, uuid. How can I do this with the newly created post_obj?

view.py

@api_view(['POST'])
def POST_create_post(request):
    serializer = PostSerializer(data=request.data)
    if serializer.is_valid():
        try:
            post_obj = serializer.save()

            try:
                if 'images' in request.FILES.keys():
                    for img in request.FILES.getlist('images'):
                        validate_image_upload(img)
                        Photo.objects.create(post=post_obj, image=img)

                if 'video' in request.FILES.keys():
                    vid = request.FILES.get('video')
                    validate_video_upload(vid)
                    Video.objects.create(post=post_obj, video=vid)
            except ValidationError as e:
                return Response(dict(error=e,
                                     user_message=error_message_generic),
                                status=status.HTTP_400_BAD_REQUEST)

        except django.db.utils.InternalError as e:
            return Response(dict(error=serializer.errors,
                                 user_message=error_message_generic),
                            status=status.HTTP_400_BAD_REQUEST)

        return Response(serializer.data, status=status.HTTP_201_CREATED)
    else:
        return Response(dict(error=serializer.errors,
                             user_message=error_message_generic),
                        status=status.HTTP_400_BAD_REQUEST)

serializer.py

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ('creator', 'body', 'uuid', 'created', 'updated_at')

models.py

class Photo(AbstractBaseModel):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    image = models.ImageField(upload_to=images_directory_path)

    @property
    def image_url(self):
        return self.image.url


class Video(AbstractBaseModel):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    video = models.FileField(upload_to=videos_directory_path)

    @property
    def video_url(self):
        return self.video.url

I have a function here

helper.py

def full_post_data_serializer(post_query_set: QuerySet):
    """
    Returns post information in news feed form to include:
    creator username, goal description, reply count, cheer count, photos
    and video
    Parameters:
        post_query_set: Current Post model object query set
    Returns:
        serializer containing all data in query set serialized
        for news feed
    """
    query_set_annotated = post_query_set.annotate(
        creator_username=F('creator__username'),
        goal_description=F('join_goal__goal__description'),
        goal_uuid=F('join_goal__goal__uuid'),
        reply_count=Count('replypost', distinct=True),
        cheer_count=Count('cheerpost', distinct=True)
    ).prefetch_related(
        Prefetch('photo_set', Photo.objects.order_by('-created'))
    )
    return FullPostDataSerializer(query_set_annotated, many=True)

serializer.py

class FullPostDataSerializer(serializers.ModelSerializer):
    image_url = serializers.SlugRelatedField(
        source='photo_set', many=True, read_only=True, slug_field='image_url'
    )
    image_uuid = serializers.SlugRelatedField(
        source='photo_set', many=True, read_only=True, slug_field='uuid'
    )
    video_url = serializers.SlugRelatedField(
        source='video_set', many=True, read_only=True, slug_field='video_url'
    )
    video_uuid = serializers.SlugRelatedField(
        source='video_set', many=True, read_only=True, slug_field='uuid'
    )
    goal_uuid = serializers.SlugField()
    creator_username = serializers.SlugField()
    reply_count = serializers.IntegerField()
    cheer_count = serializers.IntegerField()
    goal_description = serializers.SlugField()

    class Meta:
        model = Post
        fields = (
            'body', 'join_goal', 'created', 'creator_username', 'goal_description', 'reply_count', 'cheer_count',
            'image_url', 'uuid', 'type', 'image_uuid', 'creator', 'video_url', 'video_uuid', 'goal_uuid'
        )

If I could apply this to a Django model object that would have everything I need. This only works on a query set.

CodePudding user response:

For this purpose you can use SerializerMethodField. which will be read-only field.

for example in your case:-

class PostSerializer(serializers.ModelSerializer):
    image_url = serializers.SerializerMethodField()
    class Meta:
        model = Post
        fields = ('creator', 'body', 'uuid', 'created', 'updated_at' , 'image_url')
    def get_image_url(self , obj):
        # obj is Post object
        # return image_url here

Let me know if this works for you.

  • Related