Using Django's ImageField, how to store files in STATIC_ROOT? - django

Using Django's ImageField(), how would I store the image file in STATIC_ROOT rather than MEDIA_ROOT?
I realise this is a bad idea for images which are uploaded through the admin, but these images are stored with the rest of the code in git, and attached to the objects when the site is set up using a script which imports all the objects' data. The images are not added/edited/deleted after this.

You can import FileSystemStorage and specify your custom upload path and pass the FileSystemStorage object as an argument in the ImageField()
from django.core.files.storage import FileSystemStorage
from django.conf.settings import STATIC_ROOT
upload_storage = FileSystemStorage(location=STATIC_ROOT, base_url='/uploads')
class ABCModel(models.Model):
...
image = models.ImageField(upload_to='/your_image_name', storage=upload_storage)
References:
FileField - ImageField inherits from FileField
FileSystemStorage

Related

Django Upload/Download File

I am new to django. In my project I need to add user forms to upload some files and download the uploaded files.
Consider this as an online storage space.
This needs to be handled by class based views so that expansion of the views will be easy.
As of now I tried django-downloadview for objectdownloadview
https://django-downloadview.readthedocs.io/en/1.9/views/object.html
This works quite fine with the example. But I am not able to expand it for class based views for my project.
More over example is with slug I tried changing it to PK but its throwing errors.
I tried below code from django-downloadview example:-
Views.py
from django_downloadview import ObjectDownloadView
from .models import Document
default_file_view = ObjectDownloadView.as_view(model=Document)
Models.py
from django.db import models
class Document(models.Model):
slug = models.SlugField()
file = models.FileField(upload_to='object')
urls.py
from django.conf.urls import url
from .views import *
urlpatterns = [
url(r'^object/(?P<slug>[a-zA-Z0-9_-]+)/$',default_file_view,name='object'),
]
Can someone please help me here Or share a working example of simple 1 page django file upload and download stuff.
Regards,
Jaiswal

Django REST views: return images without models

I am completely new to Django REST, and I have been wasting time googling for a way to accomplish something that does not seem to be excessively difficult.
I want to define a view using the Django predefined classes for views. This view should return an image (given its name), so a URL like this would return the image example.png:
http://localhost:8000/api/v1/image/example.png
However I do not want this image to be stored in a model (it would be stored in the server as a png file). The class rest_framework.generics.RetrieveAPIView seems to suit my needs, as I can set permissions and authentication classes to restrict the access to the images, but I cannot figure out how to set the queryset if I do not have a model with my images.
Any ideas on this? Thanks and forgive my ignorance.
If I understand well, you want to check permissions before allowing access to an image.
I do not think Generic Views is the good path for you as you are not tied to a db model:
The generic views provided by REST framework allow you to quickly
build API views that map closely to your database models.
A better path could be Class Based Views, as suggested by Ivan Semochkin, something like:
class GetMyImage(APIView):
authentication_classes = (...,)
permission_classes = (...,)
def get(self, request, format=None):
with open('file path...') as fh:
return HttpResponse(fh.read(), content_type='content/image')
Of course do not forget your urls.py:
urlpatterns = [
url(r'^image/example.png$', views.GetMyImage.as_view()),
]
You can use HttpResponse to return simple json data. Please override get method in your view class.
import json
from django.http import HttpResponse
response_data = {}
response_data['image'] = 'http://localhost:8000/api/v1/image/example.png'
return HttpResponse(json.dumps(response_data), content_type="application/json")
Django will store all your media files where you have specified your root media folder to be. It will also serve them from the specified root media url.
In your settings add;
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_URL = '/media/'
Images files will be then available at 'http://localhost:8000/media/' if in your root configuration urls you add:
urlpatterns = [
url(r'^api/v1/', include('api.urls', namespace='api')),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Remember to import your configuration settings and the static method:
from django.conf import settings
from django.conf.urls.static import static

Django: sorl-thumbnail cache file is not deleted in production environment

I use django-cleanup, sorl-thumbnail in my Django project.
I have a model like this:
from sorl.thumbnail import ImageField
class Variation(BaseModel):
image = ImageField(upload_to=draft_img_upload_location)
And I use signal for sorl-thumbnail like this (recommanded by https://github.com/un1t/django-cleanup):
from django_cleanup.signals import cleanup_pre_delete
def sorl_delete(**kwargs):
from sorl.thumbnail import delete
delete(kwargs['file'])
cleanup_pre_delete.connect(sorl_delete)
So, In local environment, belows work:
1. When I delete Variation model in ADMIN PAGE, it deletes BOTH image file and image cache(created by sorl-thumbnail).
2. When I change just image file with other image in ADMIN PAGE, it delete BOTH 'prior image file' and 'prior image cache file(created by sorl-thumbnail)'.
In production environment, I used AWS S3 and cloudfront for managing static and media file. So all sorl-thumbnail cache image files are stored in S3. But whenever I changed the image file with other image file in ADMIN PAGE, the prior image cache file(created by sorl-thumbnail) still remained.
Lets say that sorl-thumbnail image url is https://example.cloudfront.net/cache/da/75/abcdefg_i_am_cached_image.jpg (from Google development tool).
In this case, there were two image files exist in S3: abcdefg.jpg and /da/75/abcdefg_i_am_cached_image.jpg
I changed abcdefg.jpg with the other image. Then, it completely deleted abcdefg.jpg in S3 storage.
Now, I accessed https://example.cloudfront.net/cache/da/75/abcdefg_i_am_cached_image.jpg in my browser and guess what! It showed this sorl-thumbnail cached images in this time!
Strange thing happened in S3 storage. When I tried to check whether abcdefg_i_am_cached_image.jpg exists in path /da/75, there was no directory named 75 right below the da folder!
In short, abcdefg_i_am_cached_image.jpg still remained in my S3 storage!
I don't know why this happened only in production environment...
This is part of settings only for production mode.
settings.py
from .partials import *
DEBUG = False
ALLOWED_HOSTS = ["*", ]
STATICFILES_STORAGE = 'spacegraphy.storage.S3PipelineCachedStorage'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME")
AWS_S3_CUSTOM_DOMAIN = os.environ.get("AWS_S3_CUSTOM_DOMAIN")
AWS_S3_URL_PROTOCOL = 'https'
AWS_S3_HOST = 's3-ap-northeast-1.amazonaws.com'
STATIC_URL = "https://this-is-my-example.cloudfront.net/"
INSTALLED_APPS += [
'storages',
'collectfast'
]
AWS_PRELOAD_METADATA = True
storage.py
from django.contrib.staticfiles.storage import CachedFilesMixin, ManifestFilesMixin
from pipeline.storage import PipelineMixin
from storages.backends.s3boto import S3BotoStorage
class S3PipelineManifestStorage(PipelineMixin, ManifestFilesMixin, S3BotoStorage):
pass
class S3PipelineCachedStorage(PipelineMixin, CachedFilesMixin, S3BotoStorage):
pass
After spending couple of hours debugging, I found out that sorl_delete signal is not called only in production environment!!.
I have no idea why this happened. I think that this one is a main problem.
And sorry for bad english (I'm not native). Really need your help. Thanks

Upload image to Firebase Storage from django models in FileField

I need to upload an image to Firebase Storage, I'm thinking do it with post_save signal or with the save method. But since Firebase is pure JS, how can I do it in the models.py? Here is the reference of how upload with Firebase Web:
https://firebase.google.com/docs/storage/web/upload-files
You're going to want to use google-cloud-storage for this:
# Import
from google.cloud import storage
# Initialize
client = storage.Client()
bucket = client.get_bucket('bucket-id-here')
# Download
blob = bucket.get_blob('remote/path/to/file.txt')
print(blob.download_as_string())
# Upload
blob2 = bucket.blob('remote/path/storage.txt')
blob2.upload_from_filename(filename='/local/path.txt')

How do I save a NamedTemporaryFile into a model FileField in Django?

I created a NamedTemporaryFile, added some content in it and now I want to save it into a model FileField.
The problem is that I get a SuspiciousOperation because the tmp directory is not within the FileSystemStorage directory.
What's the proper way to do this?
You want django to check it for you because it ensures file is put inside MEDIA_ROOT dir so it's accessible for download.
In any case you want to put files outside MEDIA_ROOT (in this case '/tmp') you should do something like this:
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location='/tmp')
class YourModel(models.Model):
...
file_field = models.FileField(..., storage=fs)
see Django documentation
I ended up doing the oposite way romke explains: I'm creating the temporary file in the MEDIA_ROOT.
Another solution could be working with the file in /tmp and then moving it to MEDIA_ROOT.
My initial confusion comes from the way forms are working with uploaded files: they are located in the /tmp directory (or in memory) and then moved automatically to the upload_to directory. I was looking for a generic way of doing it in Django.