Django ImageField에 프로그래밍 방식으로 이미지 저장
좋아, 난 거의 모든 걸 시도해 봤는데 이걸 제대로 할 수가 없어.
- ImageField가 있는 Django 모델이 있다.
- HTTP를 통해 이미지를 다운로드하는 코드가 있음(테스트 및 작동)
- 이미지가 'uppload_to' 폴더에 직접 저장됨(ImageField에 설정된 uppload_to)
- 이미 존재하는 이미지 파일 경로를 ImageField에 연결하기만 하면 된다.
나는 이 코드를 6가지 다른 방법으로 썼다.
내가 우연히 마주치는 문제는 내가 쓰고 있는 모든 코드들 때문에 다음과 같은 동작이 일어난다: (1) 짱오가 두 번째 파일을 만들고, (2) 새 파일의 이름을 바꾸고, 파일 이름 끝에 _를 추가한 다음, (3) 기본적으로 다시 명명된 빈 파일을 남겨두고 어떤 데이터도 전송하지 않는다.'uppload_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
장고가 파일을 다시 저장하지 않고 어떻게 이럴 수 있을까?내가 정말 원하는 것은 이런 취지의 것이다...
model.ImageField.path = generated_image_path
...하지만 물론 그것은 효과가 없다.
그래, 여기 있는 다른 질문들과 파일 위의 장고 문서들을 살펴봤어.
UPDATE 추가 테스트 후 윈도우즈 서버에서 Apache에서 실행될 때만 이 동작을 실행한다.XP에서 'runserver'로 실행되는 동안에는 이 동작을 실행하지 않는다.
나는 쩔쩔쩔매다
여기 XP에서 성공적으로 실행되는 코드가 있다...
f = open(thumb_path, 'r')
model.thumbnail = File(f)
model.save()
웹에서 이미지를 가져와 모델에 저장하는 코드가 있어.중요한 비트는 다음과 같다.
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()
그건 좀 혼란스럽네. 왜냐하면 내 모델에서 벗어나고 문맥에서 약간 벗어나긴 하지만, 중요한 부분은:
- 웹에서 꺼낸 이미지는 uppload_to 폴더에 저장되지 않고 urlib.urlretrieve()에 의해 임시 파일로 저장되며 나중에 폐기된다.
- ImageField.save() 메서드는 파일 이름(os.path.basename 비트)과 django.core. 파일을 취한다.파일 개체.
질문이 있거나 설명이 필요한 경우 알려주십시오.
편집: 명확히 하기 위해 필요한 가져오기 문구를 제외한 모델:
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()
모델이 아직 생성되지 않은 경우 매우 간편:
먼저 이미지 파일을 업로드 경로에 복사하십시오(다음 코드 조각에서 'path/'로 가정).
둘째, 다음과 같은 것을 사용한다.
class Layout(models.Model):
image = models.ImageField('img', upload_to='path/')
layout = Layout()
layout.image = "path/image.png"
layout.save()
1.4django에서 테스트되고 작동하며, 기존 모델에도 적용될 수 있다.
말.은 효과가 만약 조만만만을 될 것이다. TV에서 나오는 대답은 효과가 있지만, 만약 당신이 창문을 닦고 있다면, 당신은 아마도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
바이트의
다음은 잘 작동하며 파일을 특정 형식으로 변환할 수 있는 방법이다("모드 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()
이게 도움이 되길 바래.
OK. 기존 이미지 파일 경로를 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와 연결되지 않을 것이지만, 이 파일의 복사본은 imgfilename.jpg'로 uppload_to dir에 생성되어 ImageField와 연결될 것이다.
파일을 디스크에 저장하지 않는 고유한 저장소를 만든 경우:
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')
이를 위한 또 다른 가능한 방법:
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)
이러한 대답들 중 많은 것들이 시대에 뒤떨어졌고, 나는 좌절감에 많은 시간을 보냈다(나는 일반적으로 장고 & 웹 개발은 꽤 생소하다).하지만, 나는 @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)
파일을 로드하고 다시 저장하는 데 드는 오버헤드(!!)나 charfield(!!!)를 사용하지 않고 실제 파일 이름을 "설정"하고 싶다면, 이와 같은 것을 시도해 보는 것이 좋을 것이다.
model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')
이렇게 하면 실제 파일을 업로드한 것처럼 모델_instance.myfile.url과 나머지 모든 것이 켜진다.
@t-stone이 말한 것처럼, 우리가 진정으로 원하는 것은 instance.myfile.path = 'my-filename.jpg'를 설정할 수 있는 것이지만, 현재 장고는 그것을 지원하지 않는다.
이것은 당신이 찾고 있는 답이 아닐 수도 있지만, 당신은 ImageFile 대신 charfield를 사용하여 파일의 경로를 저장할 수 있다.이렇게 하면 파일을 다시 만들지 않고도 업로드된 이미지를 필드에 프로그래밍 방식으로 연결할 수 있다.
장고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()
다음을 시도해 보십시오.
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()
일한다!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)
class DemoImage(models.Model):
title = models.TextField(max_length=255, blank=False)
image = models.ImageField(blank=False, upload_to="images/DemoImages/")
import requests
import urllib.request
from django.core.files import File
url = "https://path/to/logo.jpg"
# Below 3 lines is to fake as browser agent
# as many sites block urllib class suspecting to be bots
opener = urllib.request.build_opener()
opener.addheaders = [("User-agent", "Mozilla/5.0")]
urllib.request.install_opener(opener)
# Issue command to actually download and create temp img file in memory
result = urllib.request.urlretrieve(url)
# DemoImage.objects.create(title="title", image=File(open(result[0], "rb")))
# ^^ This erroneously results in creating the file like
# images/DemoImages/path/to/temp/dir/logo_image_file
# as opposed to
# images/DemoImages/logo_image_file
# Solution to get the file in images/DemoImages/
reopen = open(result[0], "rb") # Returns a BufferedReader object of the temp image
django_file = File(reopen) # Create the file from the BufferedReader object
demoimg = DemoImage()
demoimg.title = "title"
demoimg.image.save("logo.png", django_file, save=True)
이 접근 방식은 구성된 경우 Cloudinary/S3로의 파일 업로드도 트리거
따라서 uppload_to 특성이 설정된 이미지 필드가 있는 모델이 있는 경우 다음과 같이 하십시오.
class Avatar(models.Model):
image_file = models.ImageField(upload_to=user_directory_path_avatar)
그러면 적어도 3.15django에서는 이미지를 바꾸는 것이 합리적으로 쉽다.
보기에서 이미지를 처리할 때 다음에서 이미지를 가져올 수 있음:
self.request.FILES['avatar']
InMemoryUploadedFile 유형의 인스턴스인 html 형식에 intextype 집합과 아바타 필드가 있는 경우...
<form method="post" class="avatarform" id="avatarform" action="{% url avatar_update_view' %}" enctype="multipart/form-data">
{% csrf_token %}
<input id="avatarUpload" class="d-none" type="file" name="avatar">
</form>
그런 다음 보기에서 새 이미지를 설정하는 것이 다음과 같이 쉽다(여기서 프로필은 self.request.user의 프로필 모델임).
profile.avatar.image_file.save(self.request.FILES['avatar'].name, self.request.FILES['avatar'])
image_field는 'uppload_to' 콜백 기능 때문에 profile.avatar를 저장할 필요가 없다.
Django REST 프레임워크 및 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)
나는 uuid로 이미지를 django 2 python 3에 저장한다. 왜냐하면 그것이 django가 하는 방법이기 때문이다.
import uuid
from django.core.files import File
import urllib
httpUrl = "https://miimgeurl/image.jpg"
result = urllib.request.urlretrieve(httpUrl)
mymodel.imagefield.save(os.path.basename(str(uuid.uuid4())+".jpg"),File(open(result[0], 'rb')))
mymodel.save()
admin을 사용할 경우py 문제를 해결할 수 있다(django on django):
def save_model(self, request, obj, form, change):
obj.image_data = bytes(obj.image_name.read())
super().save_model(request, obj, form, change)
모델들과 함께py:
image_name = models.ImageField()
image_data = models.BinaryField()
참조URL: https://stackoverflow.com/questions/1308386/programmatically-saving-image-to-django-imagefield
'programing' 카테고리의 다른 글
오류를 유발하는 VueJS crollBehavior() 매개 변수 (0) | 2022.03.12 |
---|---|
'제안' 변경사항을 청취하는 방법 (0) | 2022.03.12 |
reaction-remedx가 저장소를 컨텍스트에 전달하는 이유 (0) | 2022.03.12 |
Vuetify에 특정 숫자 입력 구성 요소가 있는가? (0) | 2022.03.12 |
RouterLink 특성 읽기 전용 (0) | 2022.03.12 |