Migrations and FileField storage

128 views
Skip to first unread message

Nico Benitez

unread,
Nov 12, 2014, 7:22:20 PM11/12/14
to django-users
I have a question about storage objects in a migration enabled project.

I have a project that uses a file system storage backend for storing certain model FileFields, but the location is dependent on the deployment and stored in the settings module. For example, for testing locally I have the storage root pointed at a directory under my home folder. Whenever I run makemigration, it tries to alter all the FileFields to reflect whatever the current setting is, even though this does not affect the database.

Is there a way to prevent the storage parameter from getting serialized in the migration? If not, what is a good way to handle storing files in different locations depending on a configuration, without a bunch of unnecessary migrations?

Markus Holtermann

unread,
Nov 14, 2014, 5:29:35 PM11/14/14
to django...@googlegroups.com
Hey Nico,

if you want to dynamically determin the upload / storage path you should use the "upload_to" parameter with a callable: https://docs.djangoproject.com/en/1.7/ref/models/fields/#django.db.models.FileField.upload_to inside the callable you can safely access the settings without influencing the migrations. Excluding the parameter from the migrations isn't possible by design.

/Markus

Steve Capell

unread,
Aug 25, 2015, 7:18:46 AM8/25/15
to Django users
Hi Nico,

I had the same problem when I was using this storage object:

photoStorage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'photos/original'), base_url='/photos/original')

class Photo(models.Model):
image = models.ImageField(storage=photoStorage)

The "location" argument ends up being serialized, which makes the migrations dependent on MEDIA_ROOT. To fix the problem I wrote my own subclass of FileSystemStorage:

@deconstructible
class PhotoFileSystemStorage(FileSystemStorage):
def __init__(self, photoPath):
self.photoPath = photoPath
super(PhotoFileSystemStorage,self).__init__(location=os.path.join(settings.MEDIA_ROOT, self.photoPath), base_url=self.photoPath)

def __eq__(self, other):
       return self.photoPath == other.photoPath

photoStorage = PhotoFileSystemStorage('photos/original')

When an instance of PhotoFileSystemStorage is serialized it just writes out self.photoPath, which does not depend on MEDIA_ROOT. After implementing this, the migration looks like this:

class Migration(migrations.Migration):

    dependencies = [
        ...
    ]

    operations = [
        migrations.AlterField(
            model_name='photo',
            name='image',
            field=models.ImageField(storage=myapp.models.PhotoFileSystemStorage(b'photos/original')),
        ),
    ]

You can see it does not depend on MEDIA_ROOT and won't be different if you move the project around or deploy it.


Hope this helps.


Steve


Reply all
Reply to author
Forward
0 new messages