[英]Django migrations and FileSystemStorage depending on settings
In my Django app I use a FileSystemStorage
for generated files.在我的 Django 应用程序中,我对生成的文件使用
FileSystemStorage
。 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.唯一的问题是
FileSystemStorage
的路径在 Django 迁移中是“硬编码”的。 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.因为我对开发(更改)和生产使用不同的设置,所以
manage.py makemigrations
命令通常仅因为路径更改而生成迁移,尽管数据库中的所有内容都保持不变。
I know there is a solution using a subclass of FileSystemStorage
(see my answer below), but is there a better solution?我知道有一个使用
FileSystemStorage
子类的解决方案(请参阅下面的答案),但是有更好的解决方案吗?
There is a solution involving a custom @deconstructible
subclass of FileSystemStorage
: 有一个涉及
FileSystemStorage
的自定义@deconstructible
子类的解决方案:
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. 这样Django迁移就不会注意到我的设置发生了变化。 Is there a better way though?
有更好的方法吗?
Upgrading to Django 3.1+ fixes this: https://docs.djangoproject.com/en/3.2/releases/3.1/#file-storage升级到 Django 3.1+ 解决了这个问题: https ://docs.djangoproject.com/en/3.2/releases/3.1/#file-storage
Just pass a callable into the storage argument.只需将一个可调用对象传递给存储参数即可。
from django.db import models
from django.conf import settings
from django.core.files.storage import get_storage_class
def _get_storage():
storage_class = get_storage_class(settings.MY_STORAGE_CLASS) # ie. 'django.core.files.storage.FileSystemStorage'
return storage_class()
class MyModel(models.Model):
myfile = models.FileField(max_length=255, blank=True, storage=_get_storage)
The solution is to never run makemigrations
on production. 解决方案是永远
makemigrations
在生产上运行makemigrations
。 Run migrate
all you want on production servers, but ignore warnings about running makemigrations
if they pertain to this issue. 在生产服务器上运行您想要的所有
migrate
,但如果它们与此问题相关,则忽略有关运行makemigrations
警告。
Think about it: makemigrations
generates Python code, so running it on production would be the same as developing on that server. 想想看:
makemigrations
生成Python代码,因此在生产中运行它与在该服务器上进行开发相同。 Depending on your server setup, your production site will likely serve those files correctly regardless of the makemigrations
warning. 根据您的服务器设置,无论
makemigrations
警告如何,您的生产站点都可能正确地提供这些文件。
My problem was related, but slightly different. 我的问题是相关的,但略有不同。 The storage class used by the field can change based on settings: the default locally, remote storage in production.
该字段使用的存储类可以根据设置进行更改:生产中的默认本地远程存储。 I implemented a subclass of
FileField
that ignores the storage kwarg when deconstructing the field for migration generation. 我实现的一个子类
FileField
解构场迁移代时,忽略存储 kwarg。
from django.db.models import FileField
class VariableStorageFileField(FileField):
"""
Disregard the storage kwarg when creating migrations for this field
"""
def deconstruct(self):
name, path, args, kwargs = super(VariableStorageFileField, self).deconstruct()
kwargs.pop('storage', None)
return name, path, args, kwargs
It can be used like this: 它可以像这样使用:
class MyModel(models.Model):
storage = get_storage_class(getattr(settings, 'LARGE_FILE_STORAGE', None))()
file = VariableStorageFileField(blank=True, null=True, storage=storage)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.