【问题标题】:Data Migration from ImageField to ImageField using South使用 South 从 ImageField 到 ImageField 的数据迁移
【发布时间】:2011-08-06 18:29:56
【问题描述】:

我现在尝试了几个小时来使用 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)

仍然不工作......

请帮助... :)

时光荏苒……

好的...我认为South有一些严重的问题:

这段代码在 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()

但是 Migration 文件中的这段代码并没有,转储 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()

【问题讨论】:

    标签: django django-south


    【解决方案1】:

    您可以在 South orm 中覆盖该字段的 generate_filename 方法。例如,这会将“image”字段中的所有图像复制到“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()
    

    【讨论】:

      【解决方案2】:

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

      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 小时前找到这个……这绝对是南方的东西。 TIL 你可以手动保存文件并将文件字段设置为字符串!
      【解决方案3】:

      感谢 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)
      

      【讨论】:

        【解决方案4】:

        使用 South 将 ImageField 从一个存储迁移到另一个存储

        虽然这可能不会直接回答您的问题,但我想我会为 django south imageField 迁移主题添加一些可能有用的见解(这个问题目前是网络上最好的资源)。

        South 在数据迁移中处理图像字段的一个重要问题是,作为其 ORM 冻结的副作用,它似乎假设将使用 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) 
        

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

        【讨论】:

        • file 是 Python 关键字,切勿将其用作变量。
        猜你喜欢
        • 2013-09-24
        • 1970-01-01
        • 1970-01-01
        • 2019-03-22
        • 2012-07-26
        • 2011-06-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多