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

246 投票
21 回答
196610 浏览
提问于 2025-04-15 13:45

好的,我试了几乎所有的方法,但就是无法让它工作。

  • 我有一个Django模型,其中有一个ImageField字段。
  • 我有代码可以通过HTTP下载图片(测试过,能正常工作)。
  • 图片直接保存在'upload_to'文件夹里(这个文件夹就是ImageField设置的那个)。
  • 我只需要把已经存在的图片文件路径和ImageField关联起来。

我写了大约六种不同的代码。

我遇到的问题是,我写的所有代码都会导致以下情况: (1) Django会创建一个第二个文件,(2) 将新文件重命名,在文件名后面加一个下划线,然后 (3) 不会把任何数据转移过去,结果就是一个基本上是空的重命名文件。'upload_to'路径下剩下两个文件,一个是真正的图片,另一个是图片的名字,但它是空的,当然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

……但当然这样是不行的。

是的,我也看过这里的其他问题,比如这个,还有Django文档中的文件部分。

更新 经过进一步测试,只有在Windows Server的Apache下运行时才会出现这种情况。在XP的'runserver'下运行时不会出现这种行为。

我现在很困惑。

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

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

21 个回答

43

我想说一句小提示。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 字节时会被截断。

130

如果模型还没有创建,那就简单得很:

第一步,把你的图片文件复制到上传的路径(假设这个路径是'path/',在下面的代码片段中会用到)。

第二步,使用类似下面的代码:

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

layout = Layout()
layout.image = "path/image.png"
layout.save()

这个方法在django 1.4中测试过,可能也适用于已经存在的模型。

201

我有一些代码可以从网上获取一张图片,并把它存储在一个模型里。重要的部分是:

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()

这有点让人困惑,因为这段代码是从我的模型中提取出来的,缺少了一些上下文,但重要的内容是:

  • 从网上获取的图片并没有存储在upload_to文件夹里,而是通过urllib.urlretrieve()存储为一个临时文件,之后会被丢弃。
  • ImageField.save()方法需要一个文件名(就是os.path.basename那部分)和一个django.core.files.File对象。

如果你有任何问题或者需要进一步解释,随时告诉我。

补充说明:为了更清楚,这里是模型的代码(省略了任何必要的导入语句):

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()

撰写回答