简体   繁体   English

Django ImageField:完整路径还是相对路径?

[英]Django ImageField: full or relative path?

I try to implement pictures uploading and processing in my Django project. 我尝试在我的Django项目中实现图片上传和处理。 The problem is with path for ImageField : 问题在于ImageField路径:

Option 1. 选项1。

If I use path relative to the media folder, then image.url nicely returns /media/img_name.jpg , and Django handles the pictures correctly. 如果我使用相对于media文件夹的路径,那么image.url很好地返回/media/img_name.jpg ,并且Django可以正确处理图片。 But I cannot use image.width property, it leads to the error: 但是我不能使用image.width属性,它导致错误:

SuspiciousFileOperation SuspiciousFileOperation
The joined path (/user_test/3d55d527-109d-4a07-b0f6-4de0304d41f6.jpg) is located outside of the base path component (/Users/Aivan/Desktop/Code/MyProject/media) 合并的路径(/user_test/3d55d527-109d-4a07-b0f6-4de0304d41f6.jpg)位于基本路径组件的外部(/ Users / Aivan / Desktop / Code / MyProject / media)


Option 2. 选项2。

If I use full path, then I can easily access the image.width property. 如果使用完整路径,则可以轻松访问image.width属性。 But image.url returns full path added to the media folder: http://127.0.0.1:8000/media/Users/Aivan/Desktop/Code/MyProject/media/user_test/8f3219cd-0333-4488-9d29-2c5506707afb.jpg 但是image.url返回添加到media文件夹的完整路径: http://127.0.0.1:8000/media/Users/Aivan/Desktop/Code/MyProject/media/user_test/8f3219cd-0333-4488-9d29-2c5506707afb.jpg : http://127.0.0.1:8000/media/Users/Aivan/Desktop/Code/MyProject/media/user_test/8f3219cd-0333-4488-9d29-2c5506707afb.jpg : image.url


Question: 题:

What should I do in order to properly access both image.url and image.width ? 我应该怎么才能正确地访问既做image.urlimage.width

Of course, I can always set up full path and add save the relative path in some CharField , or add an own method for relative URL extracting, but probably such solutions are bad. 当然,我总是可以设置完整路径,并将相对路径保存在某些CharField ,或者添加自己的方法来提取相对URL,但是这种解决方案可能是不好的。

I guess, that's because Django uses relative paths for media files, but to deal with images it uses Pillow which needs full paths... Maybe it's a bug? 我猜这是因为Django使用媒体文件的相对路径,但是要处理图像,它使用需要完整路径的Pillow ...也许是一个错误?


My picture class: 我的图片课:

def path_user_photo(instance, filename):
    return 'user_{0}'.format(instance.account.user.username)

class Photo(models.Model):
    image = models.ImageField(upload_to=path_user_photo)
    name = models.CharField(max_length=32, unique=True)

And it's static method for images uploading: 这是图片上传的静态方法:

    @classmethod
    def create_file(cls, fl, user, written_name, ext):
        folder = '/user_{0}'.format(user.username)
        realname = '/' + str(uuid.uuid4()) + '.' + ext
        write_path = settings.MEDIA_ROOT + folder
        # Create directory if it doesn't exist
        if not os.path.exists(write_path):
            os.makedirs(write_path)
        # Write data
        write_path = write_path + realname
        with open(write_path, 'wb+') as destination:
            for chunk in fl.chunks():
                destination.write(chunk)

        res = cls()
        # Option 1. Relative path
        res.image = folder + realname
        # Option 2. Full path
        res.image = write_path
        res.name = written_name
        res.save()
        return res

Which I call from a View like this: 我从这样的视图调用:

Photo.create_file(
    # the file
    request.FILES['file_img'],
    # current user
    request.user,
    # written name
    request.POST['written_name'],
    # real file extension
    file.name.split('.')[-1]
)

The issue here I think is that res.image = folder + realname is technically an absolute path because folder begins with a hardcoded / . 我认为这里的问题是res.image = folder + realname从技术上讲是绝对路径,因为folder以硬编码/开头。

The way to resolve, is to join the paths together using os.path.join rather than using a / explicitly, and then you should be safe to use the relative path when saving the image. 解决的方法是使用os.path.join而不是使用/显式将路径连接在一起,然后在保存图像时应该相对使用相对路径。

See below - I have commented the modified lines. 参见下文-我评论了修改后的行。

import os.path

@classmethod
def create_file(cls, fl, user, written_name, ext):
    folder = 'user_{0}'.format(user.username)  # Drop the leading slash
    realname = str(uuid.uuid4()) + '.' + ext  # Drop the leading slash
    write_path = os.path.join(settings.MEDIA_ROOT, folder)  # Join the paths
    # Create directory if it doesn't exist
    if not os.path.exists(write_path):
        os.makedirs(write_path)
    # Write data
    write_path = os.path.join(write_path, realname)  # Join the path and name
    with open(write_path, 'wb+') as destination:
        for chunk in fl.chunks():
            destination.write(chunk)

    res = cls()
    # Option 1. Relative path
    res.image = os.path.join(folder, realname)  # Join the folder and name
    res.name = written_name
    res.save()
    return res

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM