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

好吧,我已经尝试了一切,我无法得到这个工作。

  • 我有一个Django模型与上的ImageField
  • 我有代码,通过HTTP下载图像(testing和工程)
  • 图像被直接保存到“upload_to”文件夹中(upload_to是在ImageField上设置的那个)
  • 我需要做的就是将现有的图像文件path与ImageField相关联

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

我遇到的问题是我写的所有代码的结果如下:(1)Django将创build第二个文件,(2)重命名新文件,将_添加到文件末尾名称,然后(3)不传输任何数据,而将其基本上空的重命名文件。 “upload_to”path中剩下的是2个文件,一个是实际的图像,一个是图像的名称,但是是空的,当然,ImageFieldpath被设置为Django试图创build的空文件。

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

## 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文档

更新进一步testing后,它只在Windows Server上的Apache下运行时发生此行为。 当在XP的“runserver”下运行时,它不会执行这种行为。

我很难过

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

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

我有一些代码,从networking上获取图像并将其存储在模型中。 重要的是:

 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对象。

如果您有任何疑问或需要澄清,请告知我们。

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

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

超级简单,如果模型尚未创build:

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

其次 ,使用像这样的东西:

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

在Django 1.4中testing和工作,它可能也适用于现有的模型。

只是一点点的评论。 tvon答案的作品,但是,如果你在Windows上工作,你可能想打开()与文件'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字节截断。

这里有一个方法,运行良好,并允许您将文件转换为某种格式(以避免“不能写模式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) 

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

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

希望这可以帮助

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

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

好的,如果你只需要将已有的图像文件path与ImageField相关联,那么这个解决scheme可能是有帮助的:

 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目录中创build为'imgfilename.jpg',并且将与ImageField相关联。

如果你只想“设置”实际的文件名,而不会导致加载和重新保存文件(!!),或使用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目前不支持。

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

我认为最简单的解决scheme是:

 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) 

你可以试试:

 model.ImageField.path = os.path.join('/Upload', generated_image_path) 
 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() 
 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() 

您可以使用Django REST框架和python 请求库以编程方式将图像保存到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)