以编程方式将图像保存到 Django ImageField

2025-02-17 09:25:00
admin
原创
63
摘要:问题描述:好吧,我几乎尝试了所有方法但还是无法让它发挥作用。我有一个带有 ImageField 的 Django 模型我有通过 HTTP 下载图像的代码(已测试并有效)图像直接保存到“upload_to”文件夹中(upload_to 是在 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

...但这当然不起作用。

是的,我已经讨论过这里的其他问题,比如这个以及文件的 django 文档

更新
经过进一步测试,它仅在 Windows Server 上的 Apache 下运行时才会执行此行为。在 XP 上的“runserver”下运行时,它不会执行此行为。

我被难住了。

这是在 XP 上成功运行的代码...

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

解决方案 1:

我有一些代码可以从网上获取图像并将其存储在模型中。重要的部分是:

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:

如果模型还没有创建的话非常简单:

首先,将您的图像文件复制到上传路径(以下代码片段中假定 = 'path/')。

其次,使用类似如下的方法:

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

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

在 django 1.4 中测试并运行,它也可能适用于现有模型。

解决方案 3:

只是一点小评论。 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字节被截断。

解决方案 4:

好的,如果您需要做的只是将已经存在的图像文件路径与 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 关联。

解决方案 5:

这是一种效果很好且允许您将文件转换为特定格式的方法(以避免“无法将模式 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()

希望这有帮助

解决方案 6:

这些答案中有很多都已经过时了,我花了很多时间沮丧不已(我对 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)

解决方案 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)

解决方案 8:

我所做的是创建自己的存储,它不会将文件保存到磁盘:

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

解决方案 9:

如果您只想“设置”实际的文件名,而又不产生加载和重新保存文件的开销(!!),或者不使用字符字段(!!!),那么您可能需要尝试这样的操作 -

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目前不支持这一点。

解决方案 10:

这可能不是您要找的答案。但您可以使用 charfield 而不是 ImageFile 来存储文件的路径。这样,您就可以以编程方式将上传的图像关联到字段,而无需重新创建文件。

解决方案 11:

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

解决方案 12:

仅针对那些已经为这个问题苦苦挣扎了一段时间的人。我花了几个小时才明白如何才能从代码中将图像存储到 Django 中的 ImageField 中。您必须将 File 对象传递给 ImageField,如下例所示,必须打开文件,并且必须在关闭文件之前保存包含 ImageField 的模型。此示例运行良好:

from pathlib import Path
from django.core.files import File

path = Path(image_file_str_path)
with path.open(mode="rb") as f:
   yourmodel.img_field = File(f, name=path.name)
   yourmodel.save()

解决方案 13:

您可以尝试:

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

解决方案 14:

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

解决方案 15:

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

解决方案 16:

工作正常!您可以使用 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)

解决方案 17:

因此,如果您有一个带有 upload_to 属性设置的 imagefield 的模型,例如:

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'])

不需要保存profile.avatar,image_field已经保存,并由于'upload_to'回调函数保存到正确的位置。

解决方案 18:

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

解决方案 19:

如果您使用 admin.py,您可以解决问题覆盖(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()

解决方案 20:

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

解决方案 21:

您可以使用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) 
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1989  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1446  
  在当今快速发展的IT行业中,项目管理工具的选择对于项目的成功至关重要。随着技术的不断进步,项目经理们需要更加高效、灵活的工具来应对复杂的项目需求。本文将介绍2025年IT项目经理力推的10款管理工具,帮助您在项目管理中取得更好的成果。信创国产项目管理软件 - 禅道禅道是一款国产开源的项目管理软件,禅道开源版不限人数,功...
项目管理工具   0  
  在当今快速变化的商业环境中,项目管理软件已成为企业提升效率、优化资源分配和确保项目成功的关键工具。随着技术的不断进步,市场上涌现出众多功能各异的项目管理工具,每一款都有其独特的优势和适用场景。本文将深入评测2025年最受欢迎的10款项目管理软件,帮助您根据自身需求做出明智的选择。信创国产项目管理软件 - 禅道禅道是一款...
项目管理平台   2  
  产品开发效率对于企业的竞争力至关重要。在当今复杂多变的商业环境中,如何有效提升产品开发效率成为众多企业关注的焦点。产品生命周期管理(PLM)作为一种整合产品全生命周期信息的管理理念和技术,为提升产品开发效率提供了有力的支持。通过合理运用PLM,企业能够优化流程、加强协作、提高数据管理水平,从而实现产品开发的高效运作。接...
plm开发流程软件   3  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用