Hi
I’m trying to setup AWS S3 bucket and my media files, and I’m getting an error when trying to upload to my bucket
This is my settings.py
from pathlib import Path
import os
from dotenv import load_dotenv
import dj_database_url
import django_heroku
load_dotenv()
# Bucketeer settings
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
AWS_BUCKET_NAME = os.getenv('AWS_BUCKET_NAME')
AWS_REGION = os.getenv('AWS_REGION')
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
AWS_QUERYSTRING_AUTH = False
if not AWS_BUCKET_NAME:
raise ValueError("AWS_BUCKET_NAME environment variable is not set")
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = f'https://{AWS_BUCKET_NAME}.s3.amazonaws.com/'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_S3_CUSTOM_DOMAIN = f'{AWS_BUCKET_NAME}.s3.amazonaws.com'
My model is huge but to easily inspect, I’m adding the extract of ImageField
map_image = models.ImageField(blank=True, null=True, upload_to='media/')
I know the first thing is to check credentials, so I created an script and I was able to successfully upload a file, so the AWS S3 Bucket setup is correctly, what I’m failing miserably is at integrating with Django
from django.test import TestCase
# Create your tests here.
import boto3
from botocore.exceptions import NoCredentialsError
def upload_file_to_s3(file_path, bucket_name, aws_access_key_id, aws_secret_access_key, aws_region):
"""
Uploads a file to an S3 bucket.
Args:
- file_path: Path to the file to upload.
- bucket_name: Name of the S3 bucket.
- aws_access_key_id: AWS access key ID.
- aws_secret_access_key: AWS secret access key.
- aws_region: AWS region.
Returns:
- True if the file was successfully uploaded, False otherwise.
"""
try:
# Initialize S3 client
s3 = boto3.client('s3',
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
region_name=aws_region)
print(s3)
# Upload file
s3.upload_file(file_path, bucket_name, file_path)
return True
except NoCredentialsError:
print("AWS credentials not available.")
return False
except Exception as e:
print(f"Error uploading file: {e}")
return False
# Usage example:
file_path = "/workspaces/TGSProject/file.txt"
bucket_name = "mybucket" #privacy
aws_access_key_id = "zzzzzzzzzzzzz" # for privacy this is not my Key
aws_secret_access_key = "zzzzzzz" # for privacy this is not my key
aws_region = "us-east-2"
upload_successful = upload_file_to_s3(file_path, bucket_name, aws_access_key_id, aws_secret_access_key, aws_region)
if upload_successful:
print("File uploaded successfully!")
else:
print("File upload failed.")
I’m a bit frustrated, because I would imagine that if I have the default settings MEDIA_STORAGE correctly define as per the documentation, and the /media folder in my bucket that Django would work its magic behind the scene, do I have to define a function to upload?
here is the error I’m getting:
raceback (most recent call last):
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/contrib/auth/decorators.py", line 23, in _wrapper_view
return view_func(request, *args, **kwargs)
File "/workspaces/TGSProject/tracker/views.py", line 27, in add_project_view
project.save()
File "/workspaces/TGSProject/tracker/models.py", line 103, in save
super().save(*args, **kwargs)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/base.py", line 814, in save
self.save_base(
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/base.py", line 877, in save_base
updated = self._save_table(
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/base.py", line 1020, in _save_table
results = self._do_insert(
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/base.py", line 1061, in _do_insert
return manager._insert(
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/query.py", line 1805, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1821, in execute_sql
for sql, params in self.as_sql():
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1745, in as_sql
value_rows = [
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1746, in <listcomp>
[
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1747, in <listcomp>
self.prepare_value(field, self.pre_save_val(field, obj))
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1695, in pre_save_val
return field.pre_save(obj, add=True)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/fields/files.py", line 317, in pre_save
file.save(file.name, file.file, save=False)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/db/models/fields/files.py", line 93, in save
self.name = self.storage.save(name, content, max_length=self.field.max_length)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/core/files/storage/base.py", line 37, in save
name = self.get_available_name(name, max_length=max_length)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/storages/backends/s3.py", line 689, in get_available_name
return super().get_available_name(name, max_length)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/django/core/files/storage/base.py", line 77, in get_available_name
while self.exists(name) or (max_length and len(name) > max_length):
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/storages/backends/s3.py", line 541, in exists
self.connection.meta.client.head_object(Bucket=self.bucket_name, Key=name)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/botocore/client.py", line 565, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/botocore/client.py", line 958, in _make_api_call
api_params = self._emit_api_params(
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/botocore/client.py", line 1084, in _emit_api_params
self.meta.events.emit(
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/botocore/hooks.py", line 412, in emit
return self._emitter.emit(aliased_event_name, **kwargs)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/botocore/hooks.py", line 256, in emit
return self._emit(event_name, kwargs)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/botocore/hooks.py", line 239, in _emit
response = handler(**kwargs)
File "/workspaces/TGSProject/env/lib/python3.10/site-packages/botocore/handlers.py", line 282, in validate_bucket_name
if not VALID_BUCKET.search(bucket) and not VALID_S3_ARN.search(bucket):
TypeError: expected string or bytes-like object
Regards,
Francisco