Django ImageField에 이미지를 프로그래밍 방식으로 저장


203

좋아, 나는 거의 모든 것을 시도했지만 이것을 작동시킬 수 없다.

  • ImageField가있는 장고 모델이 있습니다.
  • HTTP를 통해 이미지를 다운로드하는 코드가 있습니다 (테스트 및 작동)
  • 이미지는 'upload_to'폴더 (ImageField에 설정되어있는 upload_to)에 직접 저장됩니다.
  • 이미 존재하는 이미지 파일 경로를 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

... 물론 작동하지 않습니다.

그리고 그래 내가 좋아하는 여기에 다른 질문 겪었어요 이것 뿐만 아니라에서 장고 문서 파일

업데이트 추가 테스트 후 Windows Server의 Apache에서 실행될 때만이 동작이 수행됩니다. XP에서 'runserver'로 실행하는 동안에는이 동작이 실행되지 않습니다.

나는 충격을 받았다.

XP에서 성공적으로 실행되는 코드는 다음과 같습니다.

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

또 다른 위대한 장고 질문. 나는이 문제를 운없이 해결하려고 여러 번 시도했습니다. 업로드 디렉토리에서 생성 된 파일은 원본과 비교할 때 크기가 약간 떨어져 있으며 다른 곳에 저장되어 있습니다.
westmark

업데이트가 작동하지 않습니다
AmiNadimi

답변:


166

웹에서 이미지를 가져 와서 모델에 저장하는 코드가 있습니다. 중요한 부분은 다음과 같습니다.

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

2
tvon-이 효과에 뭔가를 시도했지만, 다시 시도해 보았을 것입니다. 실제로이 코드와 매우 유사한 코드가있었습니다. (컨텍스트가 아닌 경우에도 작동 방식을 볼 수 있습니다).
T. Stone

2
URL parmatar gunk가 이미지에 첨부되지 않도록 URL 구문 분석을 사용하는 것이 좋습니다. import urlparse. os.path.basename(urlparse.urlparse(self.url).path). 게시물 주셔서 감사합니다, 도움이되었습니다.
dennmat

1
django.core.exceptions.SuspiciousOperation : '/images/10.jpg'에 대한 액세스 시도가 거부되었습니다.
DataGreed

2
@DataGreed에서는 모델의 upload_to 정의에서 슬래시 '/'를 제거해야합니다. 이것은 여기 에서 해결 되었습니다 .
tsikov

다음과 같은 오류가 발생합니다.prohibited to prevent data loss due to unsaved related object 'stream'.
Dipak

95

모델이 아직 생성되지 않은 경우 매우 쉽습니다.

먼저 이미지 파일을 업로드 경로에 복사하십시오 ( 다음 스 니펫의 = 'path /' 라고 가정 ).

둘째 , 다음과 같은 것을 사용하십시오 :

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

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

django 1.4에서 테스트되고 작동하면 기존 모델에서도 작동 할 수 있습니다.


10
정답입니다. 더 많은 투표가 필요합니다 !!! 이 솔루션도 여기 에서 발견 되었습니다.
Andrew Swihart

안녕하세요. 질문이 있습니다. Amazon S3 백엔드와 함께 django-storages를 사용하고 있습니다. 이것이 새로운 업로드를 유발합니까?
Salvatore Iovene

OP는 "Django가 파일을 복원하지 않아도됩니다"라고 묻습니다. 이것이 바로 그 답입니다!
frnhr

2
Django에는 디스크의 중복 파일 이름을 설명하는 기존 논리가 있습니다. 이 방법은 사용자가 파일 이름 중복을 검사해야하기 때문에 해당 논리를 방해합니다.
Chris Conlan

1
@Conlan : 파일 이름에 guid를 추가하십시오.
Rabih Kodeih

41

약간의 발언. tvon answer가 작동하지만 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
고마워, 나는 창문이 우리에게 직면하는 저수준 세부 사항을 잊어 버리는 경향이 있습니다.
mike_k

fml ... 리눅스 컴퓨터에서 해당 매개 변수가 전달되면 어떻게됩니까?
DMac Destroyer

1
내 질문에 대답했습니다. 스팸으로 죄송합니다. 이것에 대한 몇 가지 문서를 여기 에서 찾았 습니다 . "유닉스에서는 'b'를 모드에 추가해도 문제가되지 않으므로 모든 바이너리 파일에 대해 플랫폼 독립적으로 사용할 수 있습니다."
DMac Destroyer

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)

여기서 image는 django ImageField 또는 your_model_instance.image입니다. 사용 예는 다음과 같습니다.

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

도움이 되었기를 바랍니다


12

좋아, 이미 존재하는 이미지 파일 경로를 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 dir에 'imgfilename.jpg'로 생성되어 ImageField와 연결됩니다.


2
바이너리 파일로 열지 않습니까?
Mariusz Jamro

@MariuszJamro가 말했듯이, 다음과 같아야합니다.with open('/path/to/already/existing/file', 'rb') as f:
rahmatns

또한 물건을 저장하는 것을 잊지 마십시오 :obj.save()
rahmatns

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

그런 다음 내 모델에서 내 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'를 설정할 수 있지만 장고는 현재이를 지원하지 않습니다.


model_instance가 파일을 포함하는 모델의 인스턴스 인 경우 다른 "인스턴스"는 무엇을 의미합니까 ??
h3.

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)

3

이 답변 중 많은 부분이 구식이었고 좌절에 많은 시간을 보냈습니다 (일반적으로 Django & web dev에 익숙하지 않습니다). 그러나 @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)

2

이것은 당신이 찾고있는 대답이 아닐 수도 있습니다. 그러나 charfield를 사용하여 ImageFile 대신 파일의 경로를 저장할 수 있습니다. 이렇게하면 파일을 다시 만들지 않고도 업로드 한 이미지를 프로그래밍 방식으로 필드에 연결할 수 있습니다.


예, 나는 이것을 포기하고 MySQL에 직접 쓰거나 CharField ()를 사용하고 싶었습니다.
T. Stone

1

당신은 시도 할 수 있습니다:

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

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

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

1

일! FileSystemStorage를 사용하여 이미지를 저장할 수 있습니다. 아래 예를 확인하십시오

def upload_pic(request):
if request.method == 'POST' and request.FILES['photo']:
    photo = request.FILES['photo']
    name = request.FILES['photo'].name
    fs = FileSystemStorage()
##### you can update file saving location too by adding line below #####
    fs.base_location = fs.base_location+'/company_coverphotos'
##################
    filename = fs.save(name, photo)
    uploaded_file_url = fs.url(filename)+'/company_coverphotos'
    Profile.objects.filter(user=request.user).update(photo=photo)

이 솔루션을 사용하는 Nids에게 감사드립니다! 당신은 :) 시간 내을 많이 저장
메 흐멧 부락 이비스

0

당신은 사용할 수 있습니다 장고 REST 프레임 워크 와 파이썬 요청에 장고 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) 

0

Django 3에서는 다음과 같은 모델이 있습니다.

class Item(models.Model):
   name = models.CharField(max_length=255, unique=True)
   photo= models.ImageField(upload_to='image_folder/', blank=True)

이미지가 이미 업로드 된 경우 직접 수행 할 수 있습니다.

Item.objects.filter(...).update(photo='image_folder/sample_photo.png')

또는

my_item = Item.objects.get(id=5)
my_item.photo='image_folder/sample_photo.png'
my_item.save()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.