使用South从ImageField到ImageField的数据迁移

时间:2011-08-06 18:29:57

标签: django django-south

我现在用几个小时来尝试使用South进行最愚蠢的迁移,但不知何故,我一直在失败。我正在尝试迁移到Sorl-Thumbnail。

这是我的过渡模型:

class Deal(models.Model):
  image = ImageWithThumbsField(upload_to='deal_images',null=True,blank=True,sizes=(200,150),))
  new_image = ImageField(upload_to='new_deal_images',default='deal_images/thumb_deal_noimg.gif')

到目前为止,我的移民就是这样:

def forwards(self, orm):
  for deal in orm.Deal.objects.all():
    try:
      image_name = deal.image.name.split('/')[1]
      file_ = File(deal.image.open()) # I've also tried the method read()
      deal.new_image.save('new_deal_images/'+image_name,file_,save=False)
    except:
      deal.new_image = None  # For the default image kick in
    deal.save()

这是此代码的最新版本。所有其他人,大多数都未能正确地将图像文件放在新目录中。

帮助......:)

时间流逝......

好吧......经过几次测试,我得到了这段代码:

 def forwards(self, orm):
     for deal in orm.Deal.objects.all():
        file_content = ContentFile(deal.image.read())
        deal.new_image.save(deal.image.name,file_content) *
        deal.save()

正在复制图像并将其保存在新列(new_image)中,但问题是所有文件都保存在MEDIA_ROOT根目录中,而不是保存在所需的子目录('new_deal_images')中。我试过*行,但仍然没有运气:

deal.new_image.save('new_ideal_images/'+deal.image.name,file_content)

不能正常工作......

请帮助......:)

其他时间过去......

好吧......我认为南方有一些严重的问题:

此代码在Django Shell中完美运行,将所有文件复制到正确的位置:

 15         for deal in Deal.objects.all():
 16             image_path = deal.image.path·
 17             file_ = File(open(image_path,'rb'))
 18             deal.new_image.save(deal.image.name,file_)
 19             deal.save()

但是,迁移文件中的此代码不会转储MEDIA_ROOT根目录中的所有文件,而不会将其移动到正确的子目录中:

 15         for deal in orm.Deal.objects.all():
 16             image_path = deal.image.path·
 17             file_ = File(open(image_path,'rb'))
 18             deal.new_image.save(deal.image.name,file_)
 19             deal.save()

4 个答案:

答案 0 :(得分:4)

您可以在South orm中覆盖字段的generate_filename方法。例如,这会将“图像”字段中的所有图像复制到“new_image”字段,只需更改它们存储的目录。

for deal in orm.Deal.objects.all():
    deal._meta.get_field('new_image').generate_filename = \
        lambda inst, fn: os.path.join('new_deal_images', fn)
    img_data = SimpleUploadedfile(deal.image.name, deal.image.read())
    deal.image.close()
    setattr(deal, 'new_image', img_data)
    deal.save()

答案 1 :(得分:3)

我遇到了同样的问题,并通过直接分配路径而不是文件来解决这个问题:

for tagged in orm.ImageTag.objects.all():
   with tagged.image.content:
     filename = tagged.image.content.name.split('/')[1]
     path = default_storage.save('taggedImages/' + filename, tagged.image.content)
     tagged.imageFile = path
     tagged.save()

答案 2 :(得分:1)

感谢Mike Fogel的回答,我在将图像从一个模型移动到另一个模型的迁移中解决了这个问题:

from south.v2 import DataMigration

from .. models import upload_by_conditions
from .. models import RESOURCE_IMAGE


class Migration(DataMigration):

    def forwards(self, orm):
        src = orm['uploader.Queue']
        dst = orm['uploader.Resource']
        for item in src.objects.all():
            obj = dst(
                kind=RESOURCE_IMAGE,
                file_name=item.file_name,
                file_type=item.file_type,
                file_size=item.file_size,
            )
            # here I assign own handler!!!
            obj._meta.get_field('resource').generate_filename = upload_by_conditions
            obj.resource.save(item.file_name, item.image, save=True)

答案 3 :(得分:0)

使用South

将ImageField从一个存储迁移到另一个存储

虽然这可能不能直接回答你的问题,但我想我会在django south imageField migration主题中添加一些有用的洞察力(这个问题目前是网上最好的资源)。

South在数据迁移中处理图像字段的一个重要问题是,作为其ORM-Freezing的副作用,它似乎假设将使用DefaultStorage,因为存储不会被冻结。因此,如果您的现场有自定义存储空间,则可能无法按预期工作。但是@cberner提供了一些很好的见解,你可以直接利用存储直接保存和操作文件,然后只需设置字段的路径并保存它。撇开他的回答,我想出了以下数据迁移,将我现有的所有图像从一个存储(默认,文件系统存储)迁移到新存储(AWS):

这是从默认存储迁移到新存储(与将新存储添加到字段定义同时运行):

def forwards(self, orm):
    new_images_storage = ImagesS3Storage()

    for food in orm.Food.objects.all():
        try:
            new_file = ContentFile(food.image.read())  # south will use the default storage
            new_file_path = new_images_storage.save(food_image_upload_to(food, food.image.name), new_file)
            food.image = new_file_path
            food.save()
        except ValueError:  # food with no image
            continue

(作为参考,这是我的自定义存储,其存储桶与默认AWS存储桶不同,我的静态文件存储已使用该存储桶)

class ImagesS3Storage(S3BotoStorage):
  def __init__(self, *args, **kwargs):
    kwargs['bucket'] = getattr(settings, 'FOOD_IMAGES_BUCKET_NAME')
    super(FoodImagesS3Storage, self).__init__(*args, **kwargs) 

希望这会帮助一些失去的灵魂。