好的,我已经尝试了几乎所有的东西,但我无法让它工作。
我有一个带有 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 以及 File 上的 django 文档
更新经过进一步测试,它仅在 Windows Server 上的 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()
这有点令人困惑,因为它已从我的模型中提取出来并且有点脱离上下文,但重要的部分是:
从网络上提取的图像不存储在 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()
如果尚未创建模型,则超级简单:
首先,将您的图像文件复制到上传路径(假定 = 'path/' 在以下代码段中)。
其次,使用类似的东西:
class Layout(models.Model):
image = models.ImageField('img', upload_to='path/')
layout = Layout()
layout.image = "path/image.png"
layout.save()
在 django 1.4 中测试和工作,它可能也适用于现有模型。
只是一点意见。 tvon answer 有效,但如果您在 Windows 上工作,您可能希望使用 'rb'
open()
文件。像这样:
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()
希望这可以帮助
好的,如果您只需将已经存在的图像文件路径与 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 关联。
with open('/path/to/already/existing/file', 'rb') as f:
obj.save()
我所做的是创建自己的存储,不会将文件保存到磁盘:
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)
很多这些答案都已经过时了,我在沮丧中度过了很多小时(我对 Django 和 web 开发人员总体来说还很陌生)。但是,我发现了@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)
如果您只想“设置”实际文件名,而不会产生加载和重新保存文件(!!)的开销,或者诉诸使用字符域(!!!),您可能想尝试这样的事情 - -
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 来存储文件的路径而不是 ImageFile。通过这种方式,您可以以编程方式将上传的图像与字段相关联,而无需重新创建文件。
使用 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()
你可以试试:
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
因此,如果您有一个带有带有 upload_to 属性集的图像字段的模型,例如:
class Avatar(models.Model):
image_file = models.ImageField(upload_to=user_directory_path_avatar)
那么更改图像相当容易,至少在 django 3.15 中。
在视图中,当您处理图像时,您可以从以下位置获取图像:
self.request.FILES['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>
然后,在视图中设置新图像就像下面这样简单(其中 profile 是 self.request.user 的配置文件模型)
profile.avatar.image_file.save(self.request.FILES['avatar'].name, self.request.FILES['avatar'])
由于“upload_to”回调函数,无需保存 profile.avatar,image_field 已经保存,并保存到正确的位置。
您可以使用 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)
我在 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()
如果您使用 admin.py,您可以解决问题覆盖 (doc 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)
与models.py:
image_name = models.ImageField()
image_data = models.BinaryField()
不定期副业成功案例分享
import urlparse
。os.path.basename(urlparse.urlparse(self.url).path)
。感谢您的帖子,很有帮助。prohibited to prevent data loss due to unsaved related object 'stream'.