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
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 >
{% else %}
<div >
{% 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.
CodePudding user response:
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