How to upload image through Django admin page
I am new to Cloudinary, now trying to integrate the image upload with my Django app.
- What I want to do:
I do NOT need a page for users to upload images, instead, I want to upload images through the Django Admin page only. Then in the template retrieve the URL from the image object.
Here is the code in models.py:
class Image(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
image = CloudinaryField('image', default='media/default.jpg')
def __str__(self):
return f"{self.name}"
And in the template should be something like:
<img src="{{image.url}}" alt="{{image.name}}">
- What actually happened:
When I try to upload the image on the admin site, Django threw a 'Must supply api_key' error.
-----------------
Environment:
Request Method: POST
Request URL: http://localhost:8000/admin/tours/image/add/?_to_field=id&_popup=1
Django Version: 3.1
Python Version: 3.8.2
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'tours.apps.ToursConfig',
'users.apps.UsersConfig',
'bookings.apps.BookingsConfig',
'django_celery_beat',
'cloudinary_storage',
'cloudinary']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/contrib/admin/options.py", line 614, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 233, in inner
return view(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1653, in add_view
return self.changeform_view(request, None, form_url, extra_context)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1534, in changeform_view
return self._changeform_view(request, object_id, form_url, extra_context)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1580, in _changeform_view
self.save_model(request, new_object, form, not add)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1093, in save_model
obj.save()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/base.py", line 750, in save
self.save_base(using=using, force_insert=force_insert,
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/base.py", line 787, in save_base
updated = self._save_table(
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/base.py", line 892, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/base.py", line 930, in _do_insert
return manager._insert(
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/query.py", line 1249, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1394, in execute_sql
for sql, params in self.as_sql():
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1337, in as_sql
value_rows = [
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1338, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1338, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1289, in pre_save_val
return field.pre_save(obj, add=True)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cloudinary/models.py", line 112, in pre_save
instance_value = uploader.upload_resource(value, **options)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cloudinary/uploader.py", line 61, in upload_resource
result = upload(file, **options)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cloudinary/uploader.py", line 46, in upload
return call_cacheable_api("upload", params, file=file, **options)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cloudinary/uploader.py", line 341, in call_cacheable_api
result = call_api(action, params, http_headers, return_error, unsigned, file, timeout, **options)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cloudinary/uploader.py", line 357, in call_api
params = utils.sign_request(params, options)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cloudinary/utils.py", line 514, in sign_request
raise ValueError("Must supply api_key")
Exception Type: ValueError at /admin/tours/image/add/
Exception Value: Must supply api_key
-----------------
- What I have tried:
I used the default image field of Django to upload images, the images are uploaded without issue, while cannot figure out how to retrieve the URL of the uploaded image, then I check the CloudinaryField and realize there is a URL or build_url property, so I change the normal image field to CloudinaryField.
The settings of API credentials should be all set, no idea what else can I do to solve the issue.
DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'
CLOUDINARY_STORAGE = {
'CLOUD_NAME': 'name',
'API_KEY': 'key',
'API_SECRET': 'secret'
}
Please can anyone help, many many thanks!
-
no need i already solved!!
0 -
Hi,
Thanks for your update, glad you were able to resolve it. I see that you are using the 3rd party library Django Cloudinary Storage. Would you be able to share your solution and what you have modified to make it work in case any other user comes across this post?
0 -
Hi Aleksandar,
Thank you for your comment. Here are a few steps I did to address the issue:
1. I traced back the error message and first check the source code of utils.py where defines the sign request function as below.
Nothing was passed as params or options, so obviously cloudinary.config() method does not obtain the api_key.
def sign_request(params, options):
api_key = options.get("api_key", cloudinary.config().api_key)
if not api_key:
raise ValueError("Must supply api_key")
api_secret = options.get("api_secret", cloudinary.config().api_secret)
if not api_secret:
raise ValueError("Must supply api_secret")params = cleanup_params(params)
params["signature"] = api_sign_request(params, api_secret)
params["api_key"] = api_keyreturn params
2. Next I trace back to the config() method in cloudinary.__init__.py file, where defines the Config class used to access the settings.py and grab environment API credentials.
class Config(BaseConfig):
def __init__(self):
self._uri_scheme = URI_SCHEME
django_settings = import_django_settings()if django_settings:
self.update(**django_settings)...
3. Here the Django settings are imported via import_django_settings function, inside this function, this is how it grabs the settings:
from django.conf import settings as _django_settings
if 'CLOUDINARY' in dir(_django_settings):
return _django_settings.CLOUDINARY
else:
return None4. Then I run the shell in Django and test if I got a 'None' by running this code below, which returns false.
from django.conf import settings
'CLOUDINARY' in dir(settings)
5. So the reason is still in my settings, then I try to add config method directly in settings.py file:
cloudinary.config(
cloud_name="name",
api_key="key",
api_secret="secret"
)Now when I upload again it works and no more error. The interesting thing is that when I run step 4 I got a false, I added these settings below but it didn't work, still got a false, not sure why.
CLOUDINARY = {
'CLOUD_NAME': 'name',
'API_KEY': 'key',
'API_SECRET': 'secret'
}In conclusion, I misunderstood that the Cloudinary storage setting and Cloudinary setting are interchangeable/same, but by checking the source code of how Cloudinary grabs those settings, I realize they are different and need to set the same credentials twice for both of them. A little bit confusing since I thought the Django Cloudinary Storage is a kind of 'official' package.
0 -
Please how were you able to implement that feature? I mean to be able to upload via the admin page.
I'm experiencing issues trying to do that. I keep getting an Invalid Signature error.
0 -
Hey Michael,
The Invalid Signature error is thrown when Signed uploads are enabled on an upload preset that is enabled for the upload.
Please see our documentation below for additional information on signed/unsigned uploads.
https://cloudinary.com/documentation/upload_images#uploading_assets_to_the_cloud
https://cloudinary.com/documentation/upload_presets
This can be disabled for the upload method you are using, or alternatively, you can continue utilizing the signed uploads and provide a signature with the request being made.
0 -
I have read it. I added my cloudinary configurations in my settings.py file and still have the same issue.
0
Post is closed for comments.
Comments
6 comments