2009-08-20 147 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) 
相關問題