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

T. *_*one 192 python django django-models

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

  • 我有一个带有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
Run Code Online (Sandbox Code Playgroud)

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

model.ImageField.path = generated_image_path
Run Code Online (Sandbox Code Playgroud)

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

是的,我已经经历这里的其他问题,如走了这一个,以及对Django的DOC 文件

更新 进一步测试后,它只在Windows Server上的Apache下运行时才会出现此问题.在XP上的"runserver"下运行时,它不会执行此行为.

我很难过.

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

f = open(thumb_path, 'r')
model.thumbnail = File(f)
model.save()
Run Code Online (Sandbox Code Playgroud)

tvo*_*von 161

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

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()
Run Code Online (Sandbox Code Playgroud)

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

  • 从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()
Run Code Online (Sandbox Code Playgroud)

  • tvon - 我曾经尝试过这种效果,但也许我会再给它一次,事实上,我的代码看起来非常类似于此.(即使它脱离了上下文,我也可以看到它是如何工作的). (2认同)
  • 我建议也使用 url parse 以避免将 url 参数附加到图像上。`导入urlparse`。`os.path.basename(urlparse.urlparse(self.url).path)`。谢谢你的帖子,很有帮助。 (2认同)
  • @DataGreed你应该从模型中的upload_to定义中删除正斜杠'/'.这是[这里](http://stackoverflow.com/a/6204619/861493)解决的问题. (2认同)

Rab*_*eih 89

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

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

其次,使用类似的东西:

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

layout = Layout()
layout.image = "path/image.png"
layout.save()
Run Code Online (Sandbox Code Playgroud)

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

  • 这是正确的答案,需要更多的选票!找到了这个解决方案[这里](http://andrewbrookins.com/tech/set-the-path-to-an-imagefield-in-django-manually/). (10认同)
  • Django有一些现有的逻辑来解决磁盘上重复的文件名。此方法掩盖了这种逻辑,因为用户只能检查文件名重复。 (2认同)
  • @Conlan:将 guid 附加到文件名。 (2认同)

Tia*_*ida 41

只是一点点评论.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()
Run Code Online (Sandbox Code Playgroud)

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


小智 16

这是一个运行良好的方法,并允许您将文件转换为某种格式(以避免"无法将模式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)
Run Code Online (Sandbox Code Playgroud)

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

p = ProfilePhoto(user=user)
download_image(str(user.id), p.image, image_url)
p.save()
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助


Nic*_*rdu 11

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

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
Run Code Online (Sandbox Code Playgroud)

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

from custom_storage import CustomStorage

custom_store = CustomStorage()

class Image(models.Model):
    thumb = models.ImageField(storage=custom_store, upload_to='/some/path')
Run Code Online (Sandbox Code Playgroud)


小智 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))
Run Code Online (Sandbox Code Playgroud)

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

  • 你不应该把它作为一个二进制文件打开吗? (3认同)

s29*_*s29 7

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

model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')
Run Code Online (Sandbox Code Playgroud)

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

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


Iva*_*kin 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)
Run Code Online (Sandbox Code Playgroud)


Zay*_*aya 7

很多这些答案已经过时了,我在沮丧中花了很多时间(总的来说,我对 Django 和 Web 开发人员还是很陌生)。但是,我发现@iambibhas 提供了这个出色的要点:https ://gist.github.com/iambibhas/5051911

import requests

from django.core.files import File
from django.core.files.temp import NamedTemporaryFile


def save_image_from_url(model, url):
    r = requests.get(url)

    img_temp = NamedTemporaryFile(delete=True)
    img_temp.write(r.content)
    img_temp.flush()

    model.image.save("image.jpg", File(img_temp), save=True)

Run Code Online (Sandbox Code Playgroud)