[英]Programmatically saving image to Django ImageField
Ok, I've tried about near everything and I cannot get this to work.好的,我已经尝试了几乎所有的东西,但我无法让它工作。
I've written this code about 6 different ways.我已经用 6 种不同的方式编写了这段代码。
The problem I'm running into is all of the code that I'm writing results in the following behavior: (1) Django will make a 2nd file, (2) rename the new file, adding an _ to the end of the file name, then (3) not transfer any of the data over leaving it basically an empty re-named file.我遇到的问题是我正在编写的所有代码都会导致以下行为:(1)Django 将创建第二个文件,(2)重命名新文件,在文件末尾添加一个 _名称,然后(3)不传输任何数据,而将其基本上保留为一个空的重命名文件。 What's left in the 'upload_to' path is 2 files, one that is the actual image, and one that is the name of the image,but is empty, and of course the ImageField path is set to the empty file that Django try to create.
'upload_to' 路径中剩下 2 个文件,一个是实际图像,一个是图像名称,但为空,当然 ImageField 路径设置为 Django 尝试创建的空文件.
In case that was unclear, I'll try to illustrate:如果不清楚,我将尝试说明:
![]()
## 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<\/code><\/pre>
How can I do this without having Django try to re-store the file?如果没有 Django 尝试重新存储文件,我怎么能做到这一点? What I'd really like is something to this effect...
我真正想要的是这种效果......
![]()
model.ImageField.path = generated_image_path<\/code><\/pre>
...but of course that doesn't work. ...但当然这不起作用。
And yes I've gone through the other questions here like this one<\/a> as well as the django doc on File<\/a>是的,我已经在这里解决了其他问题,例如
这个<\/a>问题以及File<\/a>上的 django doc
Here is the code which runs successfully on XP...这是在XP上成功运行的代码...
![]()
f = open(thumb_path, 'r') model.thumbnail = File(f) model.save()<\/code><\/pre>"
I have some code that fetches an image off the web and stores it in a model.我有一些代码可以从网络上获取图像并将其存储在模型中。 The important bits are:
重要的位是:
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()
That's a bit confusing because it's pulled out of my model and a bit out of context, but the important parts are:这有点令人困惑,因为它脱离了我的模型并且有点脱离了上下文,但重要的部分是:
Let me know if you have questions or need clarification.如果您有任何疑问或需要澄清,请告诉我。
Edit: for the sake of clarity, here is the model (minus any required import statements):编辑:为了清楚起见,这里是模型(减去任何必需的导入语句):
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()
Super easy if model hasn't been created yet:如果模型尚未创建,则超级简单:
First , copy your image file to the upload path (assumed = 'path/' in following snippet).首先,将您的图像文件复制到上传路径(假设 = 'path/'在以下代码段中)。
Second , use something like:其次,使用类似的东西:
class Layout(models.Model):
image = models.ImageField('img', upload_to='path/')
layout = Layout()
layout.image = "path/image.png"
layout.save()
tested and working in django 1.4, it might work also for an existing model.在 django 1.4 中测试和工作,它可能也适用于现有模型。
Just a little remark.只是一点意见。 tvon answer works but, if you're working on windows, you probably want to
open()
the file with 'rb'
. tvon answer 有效,但是,如果您在 Windows 上工作,您可能想用
'rb'
open()
文件。 Like this:像这样:
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()
or you'll get your file truncated at the first 0x1A
byte.否则你的文件会在第一个
0x1A
字节处被截断。
Here is a method that works well and allows you to convert the file to a certain format as well (to avoid "cannot write mode P as JPEG" error):这是一种效果很好的方法,它允许您也将文件转换为某种格式(以避免“无法将模式 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)
where image is the django ImageField or your_model_instance.image here is a usage example:其中 image 是 django ImageField 或 your_model_instance.image 这里是一个用法示例:
p = ProfilePhoto(user=user)
download_image(str(user.id), p.image, image_url)
p.save()
Hope this helps希望这可以帮助
Ok, If all you need to do is associate the already existing image file path with the ImageField, then this solution may be helpfull:好的,如果您需要做的只是将已经存在的图像文件路径与 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))
Well, if be earnest, the already existing image file will not be associated with the ImageField, but the copy of this file will be created in upload_to dir as 'imgfilename.jpg' and will be associated with the ImageField.好吧,如果认真的话,已经存在的图像文件不会与ImageField相关联,但是该文件的副本将在upload_to dir中创建为'imgfilename.jpg',并将与ImageField相关联。
What I did was to create my own storage that will just not save the file to the disk:我所做的是创建自己的存储,但不会将文件保存到磁盘:
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
Then, in my models, for my ImageField, I've used the new custom storage:然后,在我的模型中,对于我的 ImageField,我使用了新的自定义存储:
from custom_storage import CustomStorage
custom_store = CustomStorage()
class Image(models.Model):
thumb = models.ImageField(storage=custom_store, upload_to='/some/path')
Another possible way to do that:另一种可能的方法是:
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)
If you want to just "set" the actual filename, without incurring the overhead of loading and re-saving the file (!!), or resorting to using a charfield (!!!), you might want to try something like this --如果您只想“设置”实际的文件名,而不会产生加载和重新保存文件的开销 (!!),或者诉诸于使用字符字段 (!!!),您可能想尝试这样的事情 - ——
model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')
This will light up your model_instance.myfile.url and all the rest of them just as if you'd actually uploaded the file.这将点亮您的 model_instance.myfile.url 和所有其余文件,就像您实际上传了文件一样。
Like @t-stone says, what we really want, is to be able to set instance.myfile.path = 'my-filename.jpg', but Django doesn't currently support that.就像@t-stone 所说,我们真正想要的是能够设置 instance.myfile.path = 'my-filename.jpg',但 Django 目前不支持。
A lot of these answers were outdated, and I spent many hours in frustration (I'm fairly new to Django & web dev in general).很多这些答案已经过时了,我在沮丧中花了很多时间(总的来说,我对 Django 和 Web 开发者还是很陌生)。 However, I found this excellent gist by @iambibhas: https://gist.github.com/iambibhas/5051911
但是,我发现了@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)
This is might not be the answer you are looking for.这可能不是您正在寻找的答案。 but you can use charfield to store the path of the file instead of ImageFile.
但是您可以使用 charfield 来存储文件的路径而不是 ImageFile。 In that way you can programmatically associate uploaded image to field without recreating the file.
通过这种方式,您可以以编程方式将上传的图像与字段相关联,而无需重新创建文件。
With Django 3, with a model such as this one:使用 Django 3,使用这样的模型:
class Item(models.Model):
name = models.CharField(max_length=255, unique=True)
photo= models.ImageField(upload_to='image_folder/', blank=True)
if the image has already been uploaded, we can directly do :如果图片已经上传,我们可以直接执行:
Item.objects.filter(...).update(photo='image_folder/sample_photo.png')
or或者
my_item = Item.objects.get(id=5)
my_item.photo='image_folder/sample_photo.png'
my_item.save()
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()
Working!在职的! You can save image by using FileSystemStorage.
您可以使用 FileSystemStorage 保存图像。 check the example below
检查下面的例子
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)
你可以试试:
model.ImageField.path = os.path.join('/Upload', generated_image_path)
Your can use Django REST framework and python Requests library to Programmatically saving image to Django ImageField您可以使用Django REST framework和 python Requests库以编程方式将图像保存到 Django ImageField
Here is a Example:这是一个例子:
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)
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)
This approach also triggers file upload to cloudinary/S3 if so configured如果这样配置,这种方法还会触发文件上传到 cloudinary/S3
So, if you have a model with an imagefield with an upload_to attribute set, such as:因此,如果您的模型具有带有 upload_to 属性集的图像字段,例如:
class Avatar(models.Model):
image_file = models.ImageField(upload_to=user_directory_path_avatar)
then it is reasonably easy to change the image, at least in django 3.15.那么更改图像相当容易,至少在 django 3.15 中是这样。
In the view, when you process the image, you can obtain the image from:在视图中,当您处理图像时,您可以从以下位置获取图像:
self.request.FILES['avatar']
which is an instance of type InMemoryUploadedFile, as long as your html form has the enctype set and a field for avatar...这是 InMemoryUploadedFile 类型的实例,只要您的 html 表单设置了 enctype 和一个头像字段...
<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>
Then, setting the new image in the view is as easy as the following (where profile is the profile model for the self.request.user)然后,在视图中设置新图像就像下面一样简单(其中 profile 是 self.request.user 的配置文件模型)
profile.avatar.image_file.save(self.request.FILES['avatar'].name, self.request.FILES['avatar'])
There is no need to save the profile.avatar, the image_field already saves, and into the correct location because of the 'upload_to' callback function.由于 'upload_to' 回调函数,不需要保存 profile.avatar,image_field 已经保存,并保存到正确的位置。
I save the image with uuid in django 2 python 3 because thats how django do it:我在 django 2 python 3 中使用 uuid 保存图像,因为这就是 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()
if use admin.py you can solve by override ( doc on django<\/a> ):如果使用 admin.py 你可以通过覆盖来解决(
django 上的文档<\/a>):
def save_model(self, request, obj, form, change):
obj.image_data = bytes(obj.image_name.read())
super().save_model(request, obj, form, change)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.