首页 文章

以编程方式将图像保存到Django ImageField

提问于
浏览
172

好吧,我已经尝试过几乎所有的东西,我无法让它工作 .

  • 我有一个带有ImageField的Django模型

  • 我有通过HTTP下载图像的代码(测试和工作)

  • 图像直接保存到'upload_to'文件夹中(upload_to是在ImageField上设置的文件夹)

  • 我需要做的就是将现有的图像文件路径与ImageField相关联

我已经用6种不同的方式编写了这段代码 .

我遇到的问题是我写的所有代码都会产生以下行为:(1)Django将生成第二个文件,(2)重命名新文件,在文件末尾添加_ name,然后(3)不传输任何数据,基本上是一个空的重命名文件 . 'upload_to'路径中剩下的是2个文件,一个是实际图像,一个是图像的名称,但是是空的,当然ImageField路径设置为Django尝试创建的空文件 .

如果不清楚,我会试着说明:

## Image generation code runs.... 
/Upload
     generated_image.jpg     4kb

## Attempt to set the ImageField path...
/Upload
     generated_image.jpg     4kb
     generated_image_.jpg    0kb

ImageField.Path = /Upload/generated_image_.jpg

如果Django没有尝试重新存储文件,我怎么能这样做呢?我真正喜欢的是这个效果......

model.ImageField.path = generated_image_path

......但当然这不起作用 .

是的,我已经完成了其他问题,如this one以及File上的django doc

UPDATE 进一步测试后,它只在Windows Server上的Apache下运行时才会出现这种情况 . 在XP上的'runserver'下运行时,它不会执行此行为 .

我很难过 .

这是在XP上成功运行的代码...

f = open(thumb_path, 'r')
model.thumbnail = File(f)
model.save()

14 回答

  • 2
    class tweet_photos(models.Model):
    upload_path='absolute path'
    image=models.ImageField(upload_to=upload_path)
    image_url = models.URLField(null=True, blank=True)
    def save(self, *args, **kwargs):
        if self.image_url:
            import urllib, os
            from urlparse import urlparse
            file_save_dir = self.upload_path
            filename = urlparse(self.image_url).path.split('/')[-1]
            urllib.urlretrieve(self.image_url, os.path.join(file_save_dir, filename))
            self.image = os.path.join(file_save_dir, filename)
            self.image_url = ''
        super(tweet_photos, self).save()
    
  • 148

    我有一些代码可以从网上获取图像并将其存储在模型中 . 重要的是:

    from django.core.files import File  # you need this somewhere
    import urllib
    
    
    # The following actually resides in a method of my model
    
    result = urllib.urlretrieve(image_url) # image_url is a URL to an image
    
    # self.photo is the ImageField
    self.photo.save(
        os.path.basename(self.url),
        File(open(result[0], 'rb'))
        )
    
    self.save()
    

    这有点令人困惑,因为它退出了我的模型并且有点脱离背景,但重要的部分是:

    • 从web中提取的图像不存储在upload_to文件夹中,而是由urllib.urlretrieve()存储为临时文件,然后丢弃 .

    • ImageField.save()方法接受一个文件名(os.path.basename位)和一个django.core.files.File对象 .

    如果您有疑问或需要澄清,请与我们联系 .

    编辑:为了清楚起见,这里是模型(减去任何必需的import语句):

    class CachedImage(models.Model):
        url = models.CharField(max_length=255, unique=True)
        photo = models.ImageField(upload_to=photo_path, blank=True)
    
        def cache(self):
            """Store image locally if we have a URL"""
    
            if self.url and not self.photo:
                result = urllib.urlretrieve(self.url)
                self.photo.save(
                        os.path.basename(self.url),
                        File(open(result[0], 'rb'))
                        )
                self.save()
    
  • 1

    如果尚未创建模型,则非常简单:

    First ,将您的图像文件复制到上传路径(假设= 'path/' 在以下代码段中) .

    Second ,使用类似:

    class Layout(models.Model):
        image = models.ImageField('img', upload_to='path/')
    
    layout = Layout()
    layout.image = "path/image.png"
    layout.save()
    

    在django 1.4中测试和工作,它也适用于现有模型 .

  • 1

    只是一点点评论 . tvon答案有效,但是,如果你正在使用Windows,你可能想要 open() 文件 'rb' . 像这样:

    class CachedImage(models.Model):
        url = models.CharField(max_length=255, unique=True)
        photo = models.ImageField(upload_to=photo_path, blank=True)
    
        def cache(self):
            """Store image locally if we have a URL"""
    
            if self.url and not self.photo:
                result = urllib.urlretrieve(self.url)
                self.photo.save(
                        os.path.basename(self.url),
                        File(open(result[0], 'rb'))
                        )
                self.save()
    

    或者你将在第一个 0x1A 字节截断你的文件 .

  • 1

    这是一个运行良好的方法,并允许您将文件转换为某种格式(以避免“无法将模式P写为JPEG”错误):

    import urllib2
    from django.core.files.base import ContentFile
    from PIL import Image
    from StringIO import StringIO
    
    def download_image(name, image, url):
        input_file = StringIO(urllib2.urlopen(url).read())
        output_file = StringIO()
        img = Image.open(input_file)
        if img.mode != "RGB":
            img = img.convert("RGB")
        img.save(output_file, "JPEG")
        image.save(name+".jpg", ContentFile(output_file.getvalue()), save=False)
    

    其中image是django ImageField或your_model_instance.image这里是一个用法示例:

    p = ProfilePhoto(user=user)
    download_image(str(user.id), p.image, image_url)
    p.save()
    

    希望这可以帮助

  • 10

    好的,如果你需要做的就是将现有的图像文件路径与ImageField相关联,那么这个解决方案可能会有所帮助:

    from django.core.files.base import ContentFile
    
    with open('/path/to/already/existing/file') as f:
      data = f.read()
    
    # obj.image is the ImageField
    obj.image.save('imgfilename.jpg', ContentFile(data))
    

    好吧,如果认真的话,现有的图像文件将不会与ImageField相关联,但是此文件的副本将在upload_to目录中创建为“imgfilename.jpg”,并将与ImageField相关联 .

  • 0

    我做的是创建我自己的存储,不会将文件保存到磁盘:

    from django.core.files.storage import FileSystemStorage
    
    class CustomStorage(FileSystemStorage):
    
        def _open(self, name, mode='rb'):
            return File(open(self.path(name), mode))
    
        def _save(self, name, content):
            # here, you should implement how the file is to be saved
            # like on other machines or something, and return the name of the file.
            # In our case, we just return the name, and disable any kind of save
            return name
    
        def get_available_name(self, name):
            return name
    

    然后,在我的模型中,对于我的ImageField,我使用了新的自定义存储:

    from custom_storage import CustomStorage
    
    custom_store = CustomStorage()
    
    class Image(models.Model):
        thumb = models.ImageField(storage=custom_store, upload_to='/some/path')
    
  • 10

    如果你只想“设置”实际文件名,而不会产生加载和重新保存文件(!!)或使用charfield(!!!)的开销,你可能想尝试这样的事情 - -

    model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')
    

    这将点亮你的model_instance.myfile.url以及其他所有内容,就像你实际上传了这个文件一样 .

    就像@ t-stone所说,我们真正想要的是能够设置instance.myfile.path ='my-filename.jpg',但Django目前不支持 .

  • 7

    我认为最简单的解决方案:

    from django.core.files import File
    
    with open('path_to_file', 'r') as f:   # use 'rb' mode for python3
        data = File(f)
        model.image.save('filename', data, True)
    
  • 0

    这可能不是您正在寻找的答案 . 但您可以使用charfield存储文件的路径而不是ImageFile . 这样,您可以以编程方式将上载的图像关联到字段,而无需重新创建文件 .

  • 5

    你可以试试:

    model.ImageField.path = os.path.join('/Upload', generated_image_path)
    
  • 38
    class Pin(models.Model):
        """Pin Class"""
        image_link = models.CharField(max_length=255, null=True, blank=True)
        image = models.ImageField(upload_to='images/', blank=True)
        title = models.CharField(max_length=255, null=True, blank=True)
        source_name = models.CharField(max_length=255, null=True, blank=True)
        source_link = models.CharField(max_length=255, null=True, blank=True)
        description = models.TextField(null=True, blank=True)
        tags = models.ForeignKey(Tag, blank=True, null=True)
    
        def __unicode__(self):
            """Unicode class."""
            return unicode(self.image_link)
    
        def save(self, *args, **kwargs):
            """Store image locally if we have a URL"""
            if self.image_link and not self.image:
                result = urllib.urlretrieve(self.image_link)
                self.image.save(os.path.basename(self.image_link), File(open(result[0], 'r')))
                self.save()
                super(Pin, self).save()
    
  • 76

    您可以使用Django REST framework和python Requests库以编程方式将图像保存到Django ImageField

    这是一个例子:

    import requests
    
    
    def upload_image():
        # PATH TO DJANGO REST API
        url = "http://127.0.0.1:8080/api/gallery/"
    
        # MODEL FIELDS DATA
        data = {'first_name': "Rajiv", 'last_name': "Sharma"}
    
        #  UPLOAD FILES THROUGH REST API
        photo = open('/path/to/photo'), 'rb')
        resume = open('/path/to/resume'), 'rb')
        files = {'photo': photo, 'resume': resume}
    
        request = requests.post(url, data=data, files=files)
        print(request.status_code, request.reason)
    
  • 14

    工作!您可以使用FileSystemStorage保存图像 . 检查下面的例子

    def upload_pic(request):
    if request.method == 'POST' and request.FILES['photo']:
        photo = request.FILES['photo']
        name = request.FILES['photo'].name
        fs = FileSystemStorage()
    ##### you can update file saving location too by adding line below #####
        fs.base_location = fs.base_location+'/company_coverphotos'
    ##################
        filename = fs.save(name, photo)
        uploaded_file_url = fs.url(filename)+'/company_coverphotos'
        Profile.objects.filter(user=request.user).update(photo=photo)
    

相关问题