In my Django app I use a FileSystemStorage
for generated files. I initialize it like this:
import os
from urlparse import urljoin
from django.conf import settings
from django.core.files.storage import FileSystemStorage
gen_files_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'generated/'), base_url=urljoin(settings.MEDIA_URL, 'generated/'))
When I want to create a new file I use:
from django.core.files.base import ContentFile
from django.db import models
def next_number():
# num = ...
return num
gen_file = models.FileField(storage=gen_files_storage)
gen_file.save('file%s.txt' % next_number(), ContentFile(''))
That works fine. The only problem is that the FileSystemStorage
's path is "hardcoded" in the Django migration. Because I use different settings for development (which changes) and production, often the manage.py makemigrations
command generates a migration only because the path changed, although everything stays the same in the database.
I know there is a solution using a subclass of FileSystemStorage
(see my answer below), but is there a better solution?
There is a solution involving a custom @deconstructible
subclass of FileSystemStorage
:
import os
from urlparse import urljoin
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.utils.deconstruct import deconstructible
@deconstructible
class MyFileSystemStorage(FileSystemStorage):
def __init__(self, subdir):
self.subdir = subdir
super(MyFileSystemStorage, self).__init__(location=os.path.join(settings.MEDIA_ROOT, self.subdir), base_url=urljoin(settings.MEDIA_URL, self.subdir))
def __eq__(self, other):
return self.subdir == other.subdir
Then I can initialize the storage like this:
import os
from urlparse import urljoin
from django.conf import settings
from django.core.files.storage import FileSystemStorage
gen_files_storage = MyFileSystemStorage('generated/')
This way Django migrations won't notice changes in my settings. Is there a better way though?