Vaibhav Singh
Vaibhav Singh

Reputation: 942

Why does django create a migration file when we change the storage attribute of FileField, when the storage type is not stored in the database?

I don't want to create a migration file whenever I change the storage of the FileField. I am getting the storage class from settings.py and it is configurable.

settings.py

Storage =  S3BotoStorage(bucket='example')

models.py

 from django.conf import settings

 class myModel(models.Model):
        file = models.FileField(upload_to='', blank=True, storage=settings.Storage)

Upvotes: 6

Views: 2075

Answers (4)

Mohsen Mahmoodi
Mohsen Mahmoodi

Reputation: 357

Yet a simpler solution is to use a callable to select the storage:

def select_storage():
    return storages[settings.STORAGE_CLASS]

file = models.FileField(upload_to='videos/%Y/%m/%d/', storage=select_storage, blank=True, null=True, verbose_name=_('file'))

This way you'll not get a new migration if you change the STORAGE_CLASS.

Upvotes: 0

Mohsen Mahmoodi
Mohsen Mahmoodi

Reputation: 357

Here is a simple solution I implemented for my video uploads that could be uploaded using different storage.

  1. Implement a storage class that acts as a wrapper to the actual storage implementation:
@deconstructible(path="travel.apps.vod.models.VideoStorage")
class VideoStorage:

    def __init__(self):
        self.storage = storages[settings.VOD_STORAGE]

    def __getattr__(self, item):
        return getattr(self.storage, item)

If you want you can inherit from Storage class, and implement all of its methods, by calling the method self.storage, but I prefer this short implementation.

  1. Use an instance of this storage on your file field:
class SomeClass(models.Model):

    file = models.File(storage=ViedeoStorage(), ....)

Note: Since the class in my implementation is not a subclass of Storage you need to use an instance as in storage=ViedeoStorage(), instead of a callable, otherwise Django will raise an error.

  1. Define different storage classes in your settings (it's up to you how to handle this part)
 STORAGES = {
            'default': {
                'BACKEND': self.DEFAULT_STORAGE_CLASS,
            },
            'staticfiles': {
                'BACKEND': 'travel.core.storage.CompressedManifestStaticFilesStorage',
            },
            'local': {
                'BACKEND': 'django.core.files.storage.FileSystemStorage',
            },
            's3': {
                'BACKEND': 'storages.backends.s3.S3Storage',
            },
        }

VOD_STORAGE = 's3'

Now whenever you change the VOD_STORAGE to select a different storage for your files, no migration will be generated.

P.S. you'll have one migration after you changed to this new storage, but this it.

Upvotes: 0

e4c5
e4c5

Reputation: 53774

TLDR: It's an empty migration, it's harmless let it be reading any further or trying different things is probably just a waste of time

When ever you make a change to a model django has to make a migration because it needs to keep track of what changes have been made to a model over time. However that does not always mean that a modification will be made in the database. The migration produced here is an empty one. Your migration probably looks something like this and you will say, hay that's not empty!!

class Migration(migrations.Migration):

    dependencies = [
        ('stackoverflow', '0010_jsonmodel'),
    ]

    operations = [
        migrations.AlterField(
            model_name='jsonmodel',
            name='jfield',
            field=stackoverflow.models.MyJsonField(),
        ),
        migrations.AlterField(
            model_name='parent',
            name='picture',
            field=models.ImageField(storage=b'Bada', upload_to=b'/home/'),
        ),
    ]

But it is!! just do

./manage.py sqlmigrate <myapp> <migration_number>

And you will find that it does not produce any SQL! Quote from the manual as suggested by @sayse

Django will make migrations for any change to your models or fields - even options that don’t affect the database - as the only way it can reconstruct a field correctly is to have all the changes in the history, and you might need those options in some data migrations later on (for example, if you’ve set custom validators).

Upvotes: 9

Swapnil
Swapnil

Reputation: 2603

Here is my interpretation to your question - You want to use the storage class (which can be changed in future) specified in your settings.py to store the files.

Suppose you specify xyz storage class in your settings.py and run makemigrations. Django will create a migration file with storage attribute as the one you had specified in the settings.py.

Now if you change the storage class in the settings.py and do not run makemigrations and upload your file, your file will get uploaded to the new storage you specified in the settings file even if you do not run makemigrations.

Hope it helps.

Upvotes: -1

Related Questions