我尝试在我的Django项目中实现图片上传和处理。问题出在ImageField
:
如果我使用相对于media
文件夹的路径,那么image.url
很好地返回/media/img_name.jpg
,并且Django正确处理图片。但是我不能使用image.width
属性,它会导致错误:
SuspiciousFileOperation
连接路径(/user_test/3d55d527-109d-4a07-b0f6-4de0304d41f6.jpg)位于基本路径组件之外(/ Users / Aivan / Desktop / Code / MyProject / media)
如果我使用完整路径,那么我可以轻松访问image.width
属性。但是image.url
会返回添加到media
文件夹的完整路径:http://127.0.0.1:8000/media/Users/Aivan/Desktop/Code/MyProject/media/user_test/8f3219cd-0333-4488-9d29-2c5506707afb.jpg
我应该怎样做才能正确访问image.url
和image.width
?
当然,我总是可以设置完整路径并在某些CharField
中添加保存相对路径,或者为相对URL提取添加自己的方法,但可能这样的解决方案很糟糕。
我想,那是因为Django使用媒体文件的相对路径,但是为了处理图像它使用Pillow需要完整的路径...也许它是一个错误?
我的图片类:
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)
它是图片上传的静态方法:
@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
我从这样的视图中调用:
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]
)
答案 0 :(得分:2)
我认为这里的问题是res.image = folder + realname
在技术上是绝对路径,因为folder
以硬编码/
开头。
解决方法是使用os.path.join
将路径连接在一起,而不是明确使用/
,然后在保存图像时使用相对路径应该是安全的。
见下文 - 我已对修改后的行进行了评论。
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