5

I am using django-rest-framework in conjuntion with django-ckeditor. I'm serving some images with absolute url-s without any problem. But images and files uploaded by ckeditor are served as relative paths, and they can't be displayed client side since it is in a different domain.

Here is an example of what I'm getting:

{
    image: "http://example.com/media/myimage.png",
    body: "<p><a href=\"/media/ckeditor/myfile.pdf\">download my file</a></p>"
}

And this is what I woul like to get:

{
    image: "http://example.com/media/myimage.png",
    body: "<p><a href="http://example.com/media/ckeditor/myfile.pdf\">download my file</a></p>"
}

Edit: This would be the model of my example:

from django.db import models
from ckeditor_uploader.fields import RichTextUploadingField

image: models.ImageField()
body: RichTextUploadingField(blank=True,null=True)
cor
  • 3,323
  • 25
  • 46

2 Answers2

8

I would use a custom serializer to fix that:

from rest_framework import serializers


def relative_to_absolute(url):
    return 'http://127.0.0.1:8000' + url


class FileFieldSerializer(serializers.Field):
    def to_representation(self, value):
        url = value.url
        if url and url.startswith('/'):
            url = relative_to_absolute(url)
        return url

When filefield.url contains a relative url, relative_to_absolute() is called to prepend the domain.

Here I just used a constant string; you can either save it in your settings, or, if Django Site framework is installed, retrieve it as follows:

from django.contrib.sites.models import Site

domain=Site.objects.get_current().domain

Sample usage of the custom serializer:

class Picture(BaseModel):
    ...
    image = models.ImageField(_('Image'), null=True, blank=True)
    ...


class PictureSerializer(serializers.ModelSerializer):
    image = FileFieldSerializer()
    class Meta:
        model = Picture
        fields = '__all__'

Variation for RichTextUploadingField

If, on the other hand, you're using RichTextUploadingField by CKEditor, your field is, basically, a TextField where an HTML fragment is saved upon images upload.

In this HTML fragment, CKEditor will reference the uploaded images with a relative path, for very good reasons:

  • your site will still work if the domain is changed
  • the development instance will work in localhost
  • after all, we're using Django, not WordPress ;)

So, I wouldn't touch it, and fix the path at runtime in a custom serializer instead:

SEARCH_PATTERN = 'href=\\"/media/ckeditor/'
SITE_DOMAIN = "http://127.0.0.1:8000"
REPLACE_WITH = 'href=\\"%s/media/ckeditor/' % SITE_DOMAIN

class FixAbsolutePathSerializer(serializers.Field):

    def to_representation(self, value):
        text = value.replace(SEARCH_PATTERN, REPLACE_WITH)
        return text

Alternatively, domain can be saved in settings:

from django.conf import settings

REPLACE_WITH = 'href=\\"%s/media/ckeditor/' % settings.SITE_DOMAIN

or retrieved from Django Site framework as follows:

from django.contrib.sites.models import Site
REPLACE_WITH = 'href=\\"{scheme}{domain}/media/ckeditor/'.format(
    scheme="http://",
    domain=Site.objects.get_current().domain
)

You might need to adjust SEARCH_PATTERN according to your CKEditor configuration; the more specific, the better.

Sample usage:

class Picture(BaseModel):
    ...
    body = RichTextUploadingField(blank=True,null=True)
    ...


class PictureSerializer(serializers.ModelSerializer):
    body = FixAbsolutePathSerializer()
    class Meta:
        model = Picture
        fields = '__all__'
Mario Orlandi
  • 5,629
  • 26
  • 29
  • Thankyou Mario for the answer! The problem is that my file is a `RichTextUploadingField` by `CKEditor`, its not a ´FileField´. The uploaded file path is mixed with more text – cor May 13 '20 at 14:08
  • Can you provide an example of an instance of RichTextUploadingField after upload ? Is it an HTML text with some tag embedded ? – Mario Orlandi May 13 '20 at 14:33
  • There is an example in my question. It is an HTML text with a `href` tag – cor May 13 '20 at 18:21
  • Ahhh now I understand: in your Model, you have an ImageField called 'image', and a RichTextUploadingField field called 'body'; the latter is a text field containing an HTML fragment provided by django-ckeditor upon upload. I think that a simple variation of the snippet I suggested could solve it: a custom serializer where the 'body' text field would be parsed to replace any occurrence of ' – Mario Orlandi May 14 '20 at 05:52
  • I will happily do it tomorrow ;) ciaooooo – Mario Orlandi May 15 '20 at 08:56
  • 1
    @cor, I updated my answer to include the RichTextUploadingField use case. I never used it, and did a quick test with a plain TextField instead. You might need to adjust SITE_DOMAIN slightly. Br – Mario Orlandi May 16 '20 at 09:01
0

You can try this

MEDIA_URL = 'https://example.com/media/'