Search code examples
djangodjango-modelsdjango-formsckeditordjango-ckeditor

Upload image to S3 bucket with django-ckeditor


I have got an Article model with "content" textarea I decided to replace this textarea(i needed an option to insert images inside form) with CK-Editor so I used django-ckeditor package

So now I got an issue - when I upload the image with CKEditorUploadingWidget() form, it saves data to local storage(I mean to the folder specified in this variable CKEDITOR_UPLOAD_PATH = "uploads/" ), however, S3 storage has been configured, so I have no clue why it doesn't work

Here my code:

 <form method="POST">
            {{ form.media }}
            {{ form|crispy }}
            {% csrf_token %}
            <button type="submit" class="btn btn-primary my-3">Add</button>
        </form>

Settings related to this topic:

    CKEDITOR_CONFIGS = {
    "default": {
        'toolbar': 'full',
        'width': 'auto'
    }
}

CKEDITOR_IMAGE_BACKEND = "pillow"
CKEDITOR_UPLOAD_PATH = "uploads/"
CKEDITOR_RESTRICT_BY_USER = True
CKEDITOR_ALLOW_NONIMAGE_FILES = False

AWS_QUERYSTRING_AUTH = False


S3_ACCESS_KEY_ID = 'secret'
S3_SECRET_ACCESS_KEY = 'secret'
S3_FILE_UPLOAD_BUCKET_NAME = 'bucket-name'
S3_FILE_UPLOAD_BUCKET_URL = 'some url'

Solution

  • If you are using S3 as the default file storage..

    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
    

    You could simply create an ArticleImage model for example..

    class ArticleImage(models.Model):
        article = models.ForeignKey(Article, on_delete=models.CASCADE, null=True)
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        image = models.ImageField(upload_to=some_dir_on_bucket_or_path_handler_function)
    

    With your default_file_storage set to S3, it will automatically handle the S3 images upload/delete for you when you perform a .save() or .delete()

    Somewhere in your logic for handling the image post request, this will upload the image.

    img = ArticleImage.objects.create(user=self.request.user, image=your_image_object)
            img.user = self.request.user
            img.save()
    

    While img.delete() will remove the image from the bucket.