可疑操作 Django
我在尝试删除上传的图片时遇到了一个问题。
错误信息大致是这样的:
SuspiciousOperation: Attempted access to '/media/artists/12-stones/154339.jpg' denied.
我查了一下,发现这个错误是因为系统在错误的地方找图片(注意第一个斜杠,/media/在文件系统中并不存在)。
我的 MEDIA_ROOT 和 MEDIA_URL 是:
MEDIA_ROOT = '/home/tsoporan/site/media/'
MEDIA_URL = "/media/
我的模型的 upload_to 参数传入了这个函数:
def get_artist_path(instance, filename):
return os.path.join('artists', slugify(instance.name), filename)
我有几个问题:
1) 我该如何解决这个问题,以便未来的上传不再出错?
2) 有没有办法在不重新上传的情况下修复我当前图片的路径?
祝好,
Titus
11 个回答
给其他人提个醒,这个问题可能是因为你要找的静态文件资源里有两个连续的'//'符号。
{{ STATIC_URL }}/style.css # Causes the issue it should be
{{ STATIC_URL }}style.css
我在设置上传路径的时候,如果前面加了一个斜杠,就出现了这个错误。
错误的写法
pic = models.ImageField(upload_to="/uploads/product_images/")
正确的写法
pic = models.ImageField(upload_to="uploads/product_images/")
好吧,稍微在代码里查找一下,发现可能有一个更深层次的错误信息在这个过程中被简化了。
在 django/core/files/storage.py 的第 210 行(这是在 1.1.1 版本中),我们看到:
def path(self, name):
try:
path = safe_join(self.location, name)
except ValueError:
raise SuspiciousOperation("Attempted access to '%s' denied." % name)
return smart_str(os.path.normpath(path))
所以这个错误应该是来自 safe_join() 函数。
在 django/utils/_os.py 中,我们有以下内容。注意倒数第三行抛出的 ValueError 错误:
===========================
def safe_join(base, *paths):
"""
Joins one or more path components to the base path component intelligently.
Returns a normalized, absolute version of the final path.
The final path must be located inside of the base path component (otherwise
a ValueError is raised).
"""
# We need to use normcase to ensure we don't false-negative on case
# insensitive operating systems (like Windows).
base = force_unicode(base)
paths = [force_unicode(p) for p in paths]
final_path = normcase(abspathu(join(base, *paths)))
base_path = normcase(abspathu(base))
base_path_len = len(base_path)
# Ensure final_path starts with base_path and that the next character after
# the final path is os.sep (or nothing, in which case final_path must be
# equal to base_path).
if not final_path.startswith(base_path) \
or final_path[base_path_len:base_path_len+1] not in ('', sep):
raise ValueError('the joined path is located outside of the base path'
' component')
return final_path
==================
嗯,“连接的路径位于基本路径组件之外”。这里面有几个 abspathu() 的调用(这个函数在这个例程的上面定义,对于 NT 系统和其他操作系统是不同的)。abspathu() 会把所有非绝对路径转换为绝对路径,方法是加上 os.cwdu(),也就是当前工作目录。
问题:你是否有一个指向媒体目录的符号链接(symlink)?换句话说,它不是项目目录的直接子目录吗?我不知道这个问题是否有效,这只是我脑子里冒出来的。
问题:传递给 safe_join() 的 self.location
和 name
的值是什么?
随便猜测一下:self.location
是不是为空?
再随便猜测一下:MEDIA_ROOT 是不是被改成了 /media/
?
如果你有自己安装的 Django(其实不难),可以在这些函数里加一些打印语句,然后作为开发服务器运行。打印输出会显示在控制台上。
更新:嗯。你说“2) self.location 和 name 的值是:/home/tsoporan/site/media 和 /media/albums/anthem-for-the-underdog/30103635.jpg”
下面这个路径有没有什么意义?
"/home/tsoporan/site/media/media/albums/anthem-for-the-underdog"
注意里面的 .../media/media/...。
另外,这是什么操作系统?Django 的版本是多少?