开发者

How do you fix the following Django Error: "Type: IOError" "Value: [Errno 13] Permission denied"

开发者 https://www.devze.com 2023-01-24 04:51 出处:网络
I am following a Django Tutorial where you are 开发者_如何学Pythonrequired to construct some image thumbnails once an image is saved in admin. I am also using Python\'s tempfile module to save a tempo

I am following a Django Tutorial where you are 开发者_如何学Pythonrequired to construct some image thumbnails once an image is saved in admin. I am also using Python's tempfile module to save a temporary file name.

However I keep running into the following error:

"Type: IOError" "Value: [Errno 13] Permission denied: 'c:\\docume~1\\myname\\locals~1\\temp\\somefilename'"

Here is the code I am using

Settings

MEDIA_ROOT = '/home/myname/projectname/media/'
MEDIA_URL = 'http://127.0.0.1:8000/media/'enter code here

models.py

from string import join
import os
from PIL import Image as PImage
from settings import MEDIA_ROOT
from os.path import join as pjoin
from tempfile import *
from string import join
from django.db import models
from django.contrib.auth.models import User
from django.contrib import admin
from django.core.files import File

class Image(models.Model):
    title = models.CharField(max_length=60, blank=True, null=True)
    image = models.FileField(upload_to="images/")
    thumbnail = models.ImageField(upload_to="images/", blank=True, null=True)
    tags = models.ManyToManyField(Tag, blank=True)
    albums = models.ManyToManyField(Album, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    rating = models.IntegerField(default=50)
    width = models.IntegerField(blank=True, null=True)
    height = models.IntegerField(blank=True, null=True)
    user = models.ForeignKey(User, null=True, blank=True)
    thumbnail2 = models.ImageField(upload_to="images/", blank=True, null=True)

def save(self, *args, **kwargs):
    #Save image dimensions
    super(Image, self).save(*args, **kwargs)
    im = PImage.open(pjoin(MEDIA_ROOT, self.image.name))
    self.width, self.height = im.size

    # large thumbnail
    fn, ext = os.path.splitext(self.image.name)
    im.thumbnail((128,128), PImage.ANTIALIAS)
    thumb_fn = fn + "-thumb2" + ext
    tf2 = NamedTemporaryFile()
    im.save(tf2.name, "JPEG")
    self.thumbnail2.save(thumb_fn, File(open(tf2.name)), save=False)
    tf2.close()

    # small thumbnail
    im.thumbnail((40,40), PImage.ANTIALIAS)
    thumb_fn = fn + "-thumb" + ext
    tf = NamedTemporaryFile()
    im.save(tf.name, "JPEG")
    self.thumbnail.save(thumb_fn, File(open(tf.name)), save=False)
    tf.close()

    super(Image, self).save(*args, **kwargs)

def size(self):
    """Image size."""
    return "%s x %s" % (self.width, self.height)

def __unicode__(self):
    return self.image.name

def tags_(self):
    lst = [x[1] for x in self.tags.values_list()]
    return str(join(lst, ', '))

def albums_(self):
    lst = [x[1] for x in self.albums.values_list()]
    return str(join(lst, ', '))

def thumbnail_(self):
    return """<a href="/media/%s"><img border="0" alt="" src="/media/%s" /></a>""" % (
                                                        (self.image.name, self.thumbnail.name))
thumbnail.allow_tags = Trueenter code here

ADMIN

class ImageAdmin(admin.ModelAdmin):
    # search_fields = ["title"]
    list_display = ["__unicode__", "title", "user", "rating", "size",  "tags_","albums_",
    "thumbnail", "created"]
list_filter = ["tags", "albums", "user"]

def save_model(self, request, obj, form, change):
    obj.user = request.user
    obj.save()

I know there are much more effective ways of using image thumbnails in Django however I would like to know why I keep getting this Permission error when thumbnails are used in this manner.

All help is greatly appreciated. Thanks.


I think this is down to the behavior of NamedTemporaryFile on Windows. From the documentation:

This function operates exactly as TemporaryFile() does, except that the file is guaranteed to have a visible name in the file system (on Unix, the directory entry is not unlinked). That name can be retrieved from the name member of the file object. Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later).

(emphasis mine)

in the line:

im.save(tf2.name, "JPEG")

save presumably tries to open the file so that it can write to it.

From the PIL docs you can pass save a file object instead of a filename so replacing the above with

im.save(tf2, "JPEG")

may help.


I regret but mikej's answer is not a solution at all as PIL supports both syntax examples. Probably, I copied the same piece of software from somewhere, and it works perfectly on my linux machines but not on windows 7. The reason is not in the image save command but rather in the following one. The command ...

self.thumbnail.save(thumb_fn, File(open(tf.name)), save=False)

... causes the permission denied error because the file is still open and cannot be opened twice at least on windows. The same error can be simulated by

copyfile(tf2.name,"some-new-filepath")

A proper workaround is

  1. Create a temporary file that is not deleted when closed
  2. Save and close the thumbnail
  3. Remove the temporary file manually

This works no matter how you save the thumbnail.

tf = NamedTemporaryFile(delete=False)
im.save(tf.name, "PNG")
#im.save(tf, "PNG")
tf.close()
copyfile(tf.name,"some-new-filepath")
os.remove(tf.name)
0

精彩评论

暂无评论...
验证码 换一张
取 消