2009-08-20 150 views
158

好吧,我试过关于一切,我无法得到这个工作。以编程方式将图像保存到Django ImageField

  • 我有一个ImageField的一个Django模型上它
  • 我有下载经由HTTP(测试和工程)
  • 的图像被直接保存到“upload_to”文件夹(upload_to图像代码是被在ImageField字段设置的一个)
  • 所有我需要做的是已经存在的映像文件的路径与ImageField的

我写这个代码大约6种不同的方式联系起来。

我遇到的问题是我写的所有代码都会导致以下行为: (1)Django将创建第二个文件,(2)重命名新文件,将_添加到文件名的末尾,然后(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以及Django的文档上File

UPDATE 进一步测试后,在Windows Server上的Apache下运行时,它只做这种行为。当在XP的'runserver'下运行时,它不会执行这种行为。

我很难过。

这里是一个成功的运行在XP代码...

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

另一个伟大的Django问题。我已经多次尝试解决这个问题,但没有运气。上传目录中创建的文件被破坏,并且与原件相比只有一小部分(存储在其他地方)。 – westmark 2009-10-08 20:48:59

+0

你的更新不起作用 – AmiNadimi 2017-07-15 11:16:24

回答

134

我有一些代码从网络中获取图像并将其存储在模型中。最重要的位是:

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

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])) 
        ) 
      self.save() 
+2

tvon - 我曾试过这种效果,但也许我会再给它一次,实际上,我看到的代码看起来非常相似。 (即使它脱节了,我可以看到它是如何工作的)。 – 2009-08-21 18:15:28

+1

我建议使用网址解析以避免获取网址霸王附加gunk图像。 '输入urlparse'。 'os.path.basename(urlparse.urlparse(self.url)。路径)'。感谢您的帖子,是有帮助的。 – dennmat 2011-09-22 19:04:28

+1

我得到django.core.exceptions.SuspiciousOperation:试图访问'/images/10.jpg'被拒绝。 – DataGreed 2012-08-13 14:07:31

2

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

+0

是的,我很想放弃这一点,并直接写入MySQL,或者只是使用CharField()。 – 2009-08-20 23:13:20

37

只是一点点的话。 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

谢谢,我倾向于忘记这些低级别细节窗口所面临的问题。 – 2011-04-14 13:45:25

+0

fml ...当这个参数传入linux机器时会发生什么? – 2011-12-10 20:46:28

+1

回答了我自己的问题...抱歉垃圾邮件。 找到了[这里]的一些文档(http://docs.python.org/tutorial/inputoutput.html#reading-and-writing-files)。 “在Unix上,向模式附加'b'并不会造成任何影响,所以您可以在所有二进制文件中独立使用它。” – 2011-12-10 20:53:04

9

我所做的就是创建自己的存储,这将只是没有将文件保存到磁盘:

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

如果你只想“集”的实际文件名,而不会产生加载和开销重新保存文件(!!),或诉诸使用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目前不支持。

+1

另请参见[建议更改为django](http://code.djangoproject.com/ticket/15590) – s29 2011-03-10 19:07:03

+0

如果model_instance是包含该文件的模型..其他“实例”代表什么? – 2011-05-07 18:12:36

+0

aah,错字 - 感谢h3 – s29 2011-05-09 11:35:13

1

你可以试试:

model.ImageField.path = os.path.join('/Upload', generated_image_path) 
+1

还不工作:https://code.djangoproject.com/ticket/15590 – 2011-12-30 13:33:03

14

这里是一个运作良好,并允许您将文件转换成一定的格式,以及(避免“不能写P模式下为JPEG”错误)的方法:

import urllib2 
from django.core.files.base import ContentFile 
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) 

其中图像是django的ImageField的或your_model_instance.image 这里是一个使用例:

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

希望这有助于

68

超级容易,如果模型没有被创建:

首先,图像文件复制到上传路径(假设= “路径/”在下面的代码片段)。

,使用类似:

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

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

测试,并在Django 1.4工作,它也可能为工作的现有模型。

+7

这是正确的回答,需要更多投票!!!找到这个解决方案[here](http://andrewbrookins.com/tech/set-the-path-to-an-imagefield-in-django-manually/)。 – 2013-05-15 03:49:34

+0

嗨。我有个问题,我在Amazon S3后端使用django-storage,这是否会触发新的上传? – 2013-09-20 09:05:44

+0

OP询问“没有让Django尝试重新存储文件”,这就是答案! – frnhr 2014-03-12 16:28:57

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

好吧,如果你需要做的就是用的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

不要将它作为二进制文件打开吗? – 2016-02-08 12:16:32

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

简单的解决方案在我看来:

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

你可以使用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) 
相关问题