简体   繁体   English

Django 迁移和 FileSystemStorage 取决于设置

[英]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.

相关问题 Django迁移中的设置 - Django settings in migrations django FileSystemStorage的动态路径 - Dynamic path for django FileSystemStorage Django - 生产环境中 FileSystemStorage 的替代方案 - Django - Alternative for FileSystemStorage in Production Environment Django:在迁移期间的运行时更改设置值 - Django: Change settings value during run-time in migrations 如何使用 Django 中的 FileSystemStorage 上传由 OpenCV 修改的图像文件? - How to upload an Image File modified by OpenCV using FileSystemStorage in Django? Django迁移 - Django migrations 根据操作系统自定义Django settings.py文件 - Customize the Django settings.py file depending on the OS 当我尝试在Django中进行迁移时,出现未定义DJANGO_SETTINGS_MODULE的错误 - When I try to make migrations in django I get an error of undefined DJANGO_SETTINGS_MODULE 如何使用 formtools 向导从 Django FileSystemStorage 中检索以多步骤形式上传的文件 - How to retrieve files from Django FileSystemStorage uploaded in a multisteps form using formtools wizard 没有使用 Django 的 FileSystemStorage 创建“媒体”文件夹。 如果手动制作文件也不会保存 - “Media” folder not being created with Django's FileSystemStorage. Files don't get saved if made manually either
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM