Images are uploaded into S3 but URL within django application is not displaying correctly

Problem

I am able to upload images into S3, however the structure of the URL within my django app is not structured properly.
The URL appears like this: http://localhost:8000/plants/https://'%s.s3.amazonaws.com'%AWS_STORAGE_BUCKET_NAME/media/plant_images/image.jpeg
However, I want it to appear as https://opensprouts-dev-media.s3.amazonaws.com/media/plant_images/images.jpeg

enter image description here

Context
I have a model that allows me to upload multiple images. I think I need to rewrite the way I call for the image within my template, or within my model. After reading through Django documentation and other stackoverflow questions, I'm not sure how to resolve this issue.

settings.py/base.py

# MEDIA
# ------------------------------------------------------------------------------
USE_S3 = os.getenv('USE_S3') == 'TRUE'

AWS_ACCESS_KEY_ID = config('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = config('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = config('AWS_STORAGE_BUCKET_NAME')
AWS_QUERYSTRING_AUTH = config('AWS_QUERYSTRING_AUTH')
AWS_S3_CUSTOM_DOMAIN = config('AWS_S3_CUSTOM_DOMAIN')
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = config('AWS_LOCATION')
PUBLIC_MEDIA_LOCATION = 'media'
AWS_QUERYSTRING_AUTH = False

MEDIA_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATIN)
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

The section of my template that is calling for the URL {{ image.images.url }}

{% for image in plant.plant_images.all %}
{% if forloop.first %}
<div class="carousel-item active">
{% else %}
<div class="carousel-item">
{% endif %}
    <img src="{{ image.images.url }}" alt="{{ plant.name }}">
</div>
{% endfor %}
</div>

models.py

import datetime

from django.conf import settings
from django.db import models
from django.utils import timezone
from django.template.defaultfilters import slugify
from django.urls import reverse
from django_quill.fields import QuillField

# Create your models here.

class Plant(models.Model):
    name = models.CharField(max_length=120)
    slug = models.SlugField(null=False, unique=True)
    description = models.TextField()

    def __str__(self):
        return self.name

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def get_absolute_url(self):
        return reverse("plant_detail", kwargs={"slug": self.slug})

class PlantImage(models.Model):
    plant = models.ForeignKey(Plant, default=None, on_delete=models.CASCADE, related_name="plant_images")
    images = models.ImageField(upload_to = 'plant_images/')
 
    def __str__(self):
        return self.plant.name

views.py

from .models import Plant, PlantImage

def plant_index(request):
    plant_objects = Plant.objects.all()
    context = {'plant_objects': plant_objects}
    return render(request, 'plants/plant_index.html', context)

class PlantDetailView(DetailView):
    model = Plant
    template_name = 'plants/plant_detail.html'
    slug = 'slug'

    def get_context_data(self, **kwargs):
        context = super(PlantDetailView, self).get_context_data(**kwargs)
        context['plant_images'] = PlantImage.objects.all()
        return context

plant_detail = PlantDetailView.as_view()

I can see the images are successfully being stored in s3 after I upload them via my Django backend UI, however the URL is not allowing me to display the images on the page correctly. enter image description here

You can use boto3 config to upload your images and that will not add http://localhost:8000/plants in your base url of image.

from storages.backends.s3boto import S3BotoStorage

class PublicMediaStorage(S3Boto3Storage):
    location = "media"
    default_acl = "public-read"
    file_overwrite = False
    custom_domain = False

and use the above class in your model using storage params of django model

class PlantImage(models.Model):
    plant = models.ForeignKey(Plant, default=None, on_delete=models.CASCADE, related_name="plant_images")
    images = models.ImageField(storage=PublicMediaStorage() ,upload_to = 'plant_images/')
 
    def __str__(self):
        return self.plant.name
Back to Top