How to add an image or an audio file upload support to RichTextUploadField through Django REST?

Viewed 325

I have a RichTextUploadField in my models which is added by ckeditor's library. I want to add a support to create simple html field related content which includes some img and audio tags. I have added a support to upload html content through admin just have no idea how to add support to create through API endpoint?

models.py

from ckeditor_uploader.fields import RichTextUploadingField

class Part(models.Model):
    title = models.CharField(max_length=255)
    textfield = RichTextUploadingField()
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ('-created_at', )

    def __str__(self):
        return str(self.explanation)

settings.py (!some parts)

...
INSTALLED_APPS = [
    ...
    # third party installed apps
    'rest_framework',
    'ckeditor',
    'ckeditor_uploader',
    ...
]

CKEDITOR_UPLOAD_PATH = "uploads/"
...
### I am using html5audio package to upload audios
CKEDITOR_CONFIGS = {
    'default': {
        'toolbar': 'full',
        'extraPlugins': ','.join(
            [
                'html5audio',
            ]
        ),
    },
}

Question: How can I add support to create HTML content through an REST API endpoint?

1 Answers

I think you should implement two different endpoints which you can upload audio or image files. Note you should configure upload_to to the folder where ckeditor has an access. Following my custom implementation for what you are asking.

models.py

from django.db import models

import os
from uuid import uuid4


def get_custom_audio_upload_path(filename, instance):
    ext = str(filename).split('.')[-1]
    filename = f'{uuid4()}.{ext}'
    return os.path.join("uploads/custom_audio/", filename)


def get_custom_image_upload_path(filename, instance):
    ext = str(filename).split('.')[-1]
    filename = f'{uuid4()}.{ext}'
    return os.path.join("uploads/custom_image/", filename)


class CustomAudio(models.Model):
    audio = models.FileField(upload_to=get_custom_audio_upload_path)

    def __str__(self):
        return self.audio.name


class CustomImage(models.Model):
    image = models.ImageField(upload_to=get_custom_image_upload_path)

    def __str__(self):
        return self.image.name

serializers.py

class CustomAudioSerializer(ModelSerializer):
    class Meta:
        model = CustomAudio
        fields = '__all__'


class CustomImageSerializer(ModelSerializer):
    class Meta:
        model = CustomImage
        fields = '__all__'

views.py

...

class CustomAudioViewSet(ModelViewSet):
    queryset = CustomAudio.objects.all()
    serializer_class = CustomAudioSerializer
    permission_classes = [IsAdminUser, ]

    def create(self, request, *args, **kwargs):
        data = request.data
        serialized = CustomAudioSerializer(data=data)
        if serialized.is_valid():
            serialized.save()
            return Response(serialized.data, status=status.HTTP_201_CREATED)
        return Response(serialized.errors, status=status.HTTP_400_BAD_REQUEST)

    def get_permissions(self):
        if self.action == "list" or self.action == "retrieve":
            permission_classes = [AllowAny, ]
        else:
            permission_classes = [AllowAny, ]
        return [permission() for permission in permission_classes]


class CustomImageViewSet(ModelViewSet):
    queryset = CustomImage.objects.all()
    serializer_class = CustomImageSerializer
    permission_classes = [IsAdminUser]

    def create(self, request, *args, **kwargs):
        data = request.data
        serialized = CustomAudioSerializer(data=data)
        if serialized.is_valid():
            serialized.save()
            return Response(serialized.data, status=status.HTTP_201_CREATED)
        return Response(serialized.errors, status=status.HTTP_400_BAD_REQUEST)

    def get_permissions(self):
        if self.action == "list" or self.action == "retrieve":
            permission_classes = [AllowAny, ]
        else:
            permission_classes = [AllowAny, ]
        return [permission() for permission in permission_classes]

urls.py

from rest_framework.routers import SimpleRouter
from django.urls import path, include
from someapp.views import CustomImageViewSet, CustomAudioViewSet

router = SimpleRouter()
router.register('customaudio', CustomAudioViewSet)
router.register('customimage', CustomImageViewSet)

urlpatterns = [
    path('', include(router.urls)
]

Just a little explanation: when you upload a audio or image you should make a post request to the endpoint and you will get url for the result and just embed it into tag. It should retrieve it from your media folder.

Related