问题描述
使用 Django 2.2 和 python 3.7,部署在 Heroku 上
我有一个带有灵活存储位置的文件字段的模型,具体取决于应用环境(开发中的本地文件系统,生产中的 S3)。
- 创建新模型
- 使用数据迁移将数据从旧模型复制到新模型
- 删除旧模型
数据迁移在本地(使用本地文件系统存储)运行良好,但在 Heroku 测试服务器(文件存储在 S3 存储桶中)上失败。我收到如下错误消息:
FileNotFoundError: [Errno 2] No such file or directory: '/app/private/recalls/user_74/PDIR_BBUY__9e8c995f-512f-446a-9e99-e95f0de1a4ff.pdf'
相关代码如下
现有的“旧”模型:
from django.db import models
from myapp.storage_backends import storages_location,upload_file_rename
class OldUpload(models.Model):
recall_file = models.FileField(
validators=[FileExtensionValidator(allowed_extensions=['pdf'],message=RECALL_FILE_EXTENSION_MESSAGE)],storage=storages_location(),upload_to=recall_file_rename
)
myapp.storage_backends(基于 Local filesystem as a remote storage in Django):
import os
import uuid
from storages.backends.s3boto3 import S3Boto3Storage
from django.conf import settings
from django.core.files.storage import FileSystemStorage,get_storage_class
class PrivateS3MediaStorage(S3Boto3Storage):
location = settings.PRIVATE_MEDIA_LOCATION
default_acl = 'private'
file_overwrite = True
custom_domain = False
bucket_name = settings.AWS_MEDIA_BUCKET_NAME
class PrivateFileSystemStorage(FileSystemStorage):
location = @R_404[email protected](settings.MEDIA_ROOT,settings.PRIVATE_MEDIA_LOCATION)
def storages_location():
media_storage = None
if settings.SITE_NAME == 'LOCAL':
base_url = @R_404[email protected](settings.MEDIA_URL.rstrip('/'),settings.PRIVATE_MEDIA_LOCATION)
PrivateFileSystemStorage(base_url=base_url)
else:
media_storage = PrivateS3MediaStorage()
return media_storage
def upload_file_rename(instance,filename):
"""
Makes file names unique and splits into directories based on user id.
"""
base_name,extension = @R_404[email protected](filename)
filename = '{}__{}'.format(base_name,uuid.uuid4())
return @R_404[email protected](
u'recalls',u'user_{}'.format(instance.user.pk),u'{filename}{ext}'.format(filename=filename,ext=extension)
)
新模型:
from django.db import models
from constrainedfilefield.fields import ConstrainedFileField
from myapp.storage_backends import storages_location,upload_file_rename
class NewUpload(models.model):
uploaded_file = ConstrainedFileField(
blank=True,null=True,upload_to=upload_file_rename,content_types=ALLOWED_FILE_CONTENT_TYPES,max_upload_size=settings.MAX_UPLOAD_LIMIT
)
数据迁移:
class Migration(migrations.Migration):
dependencies = [...]
def copy_recall_notice_to_upload(apps,schema_editor):
from django.core.files import File
oldupload_model = apps.get_model("accounts","oldupload")
newupload_model = apps.get_model("accounts","newupload")
current_uploads = oldupload_model.objects.all()
for old_upload in current_uploads:
new_instance = newupload_model()
...(copy other fields)...
new_file = File(old_upload.recall_file.open(),name='filename')
new_instance.uploaded_file = new_file
new_instance.save()
def reverse(apps,schema_editor):
...
operations = [
migrations.RunPython(copy_recall_notice_to_upload,reverse)
]
当迁移在 Heroku 服务器上运行时,old_upload.recall_file.open()
试图打开本地文件,而不是 S3 上的文件。错误信息:
FileNotFoundError: [Errno 2] No such file or directory: '/app/private/recalls/user_74/PDIR_BBUY__9e8c995f-512f-446a-9e99-e95f0de1a4ff.pdf'
旧表中的文件不是很多,因此最简单的方法可能是为文件创建新表,然后在迁移后使用 shell 脚本复制文件。不过,我想知道为什么外部存储在迁移中不起作用。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)