我有这样定义的模型的一部分:
logo_image = models.ImageField(upload_to=lambda i, fn: "logo_%s"%(fn), height_field="logo_image_height", width_field="logo_image_width")
并对upload_to 函数有疑问。
根据django 的 FileField.upload_to 文档,第二个参数filename
是“最初赋予文件的文件名”。
现在,了解 HTTP、文件上传等,最终用户的客户端可以轻松伪造文件名。特别是,终端客户端不能上传一个名为“/etc/passwd”的文件,例如,如果我使用我的幼稚代码(lambda i, fn: "logo_%s"%(fn)
),生成的文件不会上传到/etc/passwd
吗?我需要转义filename
参数吗?
#using django's example of using full paths in settings module,
#MEDIA_ROOT="/tmp/media"
>>> os.path.join("/tmp/media/", "apple.jpg")
'/tmp/media/apple.jpg'
>>> os.path.join("/tmp/media/", "/etc/passwd")
'/etc/passwd'
感谢您的任何建议/答案/澄清。
编辑
要查看的重要方法在 files.py 中,靠近第 272 行:
272 def get_directory_name(self):
273 return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
274
275 def get_filename(self, filename):
276 return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
277
278 def generate_filename(self, instance, filename):
279 return os.path.join(self.get_directory_name(), self.get_filename(filename))
定义自定义upload_to
替换generate_filename
() 如下所示:
226 if callable(upload_to):
227 self.generate_filename = upload_to
然后,在save() 方法中:
89 def save(self, name, content, save=True):
90 name = self.field.generate_filename(self.instance, name)
91 self.name = self.storage.save(name, content)
并且返回的文件名被传递给存储类,最终调用 _os.py util 模块safe_join中的 django 替换函数。
该功能似乎减轻了我的恐惧:
24 def safe_join(base, *paths):
25 """
26 Joins one or more path components to the base path component intelligently.
27 Returns a normalized, absolute version of the final path.
28
29 The final path must be located inside of the base path component (otherwise
30 a ValueError is raised).
31 """