代码之家  ›  专栏  ›  技术社区  ›  T. Stone

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

  •  176
  • T. Stone  · 技术社区  · 15 年前

    好吧,我几乎什么都试过了,但我不能让它工作。

    • 我有一个Django模型,上面有一个ImageField
    • 我有通过HTTP下载图像的代码(经过测试并有效)
    • 图像直接保存到“上载到”文件夹中(上载到是在ImageField上设置的)
    • 我需要做的就是将已经存在的图像文件路径与ImageField关联起来

    我已经用6种不同的方式编写了这段代码。

    我遇到的问题是,我正在编写的所有代码都会导致以下行为: (1) Django将生成第二个文件,(2)重命名新文件,在文件名末尾添加一个uu,然后(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

    使现代化 经过进一步测试后,它仅在Windows服务器上在Apache下运行时才执行此行为。在XP上的“runserver”下运行时,它不会执行此行为。

    我被难住了。

    下面是在XP上成功运行的代码。。。

    f = open(thumb_path, 'r')
    model.thumbnail = File(f)
    model.save()
    
    14 回复  |  直到 8 年前
        1
  •  186
  •   tvon    6 年前

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

    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()将其存储为tempfile,然后将其丢弃。
    • 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
  •  110
  •   Rabih Kodeih    12 年前

    如果尚未创建模型,则超级简单:

    ,将图像文件复制到上载路径(假定为= “路径/” 在下面的代码片段中)。

    第二 ,使用类似于:

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

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

        3
  •  42
  •   M.javid munsu    7 年前

    只是一句话。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 字节

        4
  •  18
  •   Tim Tisdall    7 年前

    以下是一种工作良好的方法,允许您将文件转换为特定格式(以避免“无法将模式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)
    

    下面是一个使用示例:

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

    希望这有帮助

        5
  •  15
  •   rmnff    11 年前

    好的,如果您只需要将现有的图像文件路径与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关联。

        6
  •  11
  •   Nicu Surdu Robert Laverty    7 年前

    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
  •  10
  •   Ivan Semochkin    4 年前

    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
  •  7
  •   s29    14 年前

    model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')
    

        9
  •  7
  •   Zaya    5 年前

    这些答案中有很多都过时了,我花了很多时间在沮丧中(我对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)
    
    
        10
  •  2
  •   Mohamed    15 年前

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

        11
  •  2
  •   Skratt    5 年前

    与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
  •  1
  •   pmr    12 年前

    model.ImageField.path = os.path.join('/Upload', generated_image_path)
    
        13
  •  1
  •   sawan gupta    12 年前
    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()
    
        14
  •  1
  •   ArK Sheeba Nancy    8 年前
    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()
    
        15
  •  1
  •   Nids Barthwal    6 年前

    工作 您可以使用文件系统存储来保存映像。 检查下面的示例

    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)
    
        16
  •  0
  •   Soumya    5 年前
    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,这种方法也会触发文件上传

        17
  •  0
  •   miller the gorilla    4 年前

    class Avatar(models.Model):
        image_file = models.ImageField(upload_to=user_directory_path_avatar)
    

    至少在Django3.15中,更改图像是相当容易的。

    在视图中,处理图像时,可以从以下位置获取图像:

    self.request.FILES['avatar']
    

    这是InMemoryUploadedFile类型的实例,只要您的html表单具有enctype集和avatar字段。。。

        <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,图像_字段已经保存,并且由于“upload_to”回调函数而保存到正确的位置。

        18
  •  0
  •   Arnaud P    4 年前

    你可以用 Django REST framework 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) 
    
        19
  •  0
  •   user3486626    4 年前

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