Django:如何允许可疑文件操作/复制文件

时间:2014-02-25 15:52:02

标签: python django

我想做一个SuspiciousFileOperation,默认情况下django不允许这样做。

我正在编写一个命令(通过manage.py importfiles运行),以便在我自己编写的Django文件存储库中导入真实文件系统上的给定目录结构。

我想,这是我的相关代码:

def _handle_directory(self, directory_path, directory):
    for root, subFolders, files in os.walk(directory_path):
        for filename in files:
            self.cnt_files += 1
            new_file = File(directory=directory, filename=filename, file=os.path.join(root, filename),
                 uploader=self.uploader)
            new_file.save()

回溯是:

Traceback (most recent call last):
  File ".\manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line 399, in execute_from_command_line
    utility.execute()
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line 392, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Python27\lib\site-packages\django\core\management\base.py", line 242, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "C:\Python27\lib\site-packages\django\core\management\base.py", line 285, in execute
    output = self.handle(*args, **options)
  File "D:\Development\github\Palco\engine\filestorage\management\commands\importfiles.py", line 53, in handle
    self._handle_directory(args[0], root)
  File "D:\Development\github\Palco\engine\filestorage\management\commands\importfiles.py", line 63, in _handle_directory
    new_file.save()
  File "D:\Development\github\Palco\engine\filestorage\models.py", line 157, in save
    self.sha512 = hashlib.sha512(self.file.read()).hexdigest()
  File "C:\Python27\lib\site-packages\django\core\files\utils.py", line 16, in <lambda>
    read = property(lambda self: self.file.read)
  File "C:\Python27\lib\site-packages\django\db\models\fields\files.py", line 46, in _get_file
    self._file = self.storage.open(self.name, 'rb')
  File "C:\Python27\lib\site-packages\django\core\files\storage.py", line 33, in open
    return self._open(name, mode)
  File "C:\Python27\lib\site-packages\django\core\files\storage.py", line 160, in _open
    return File(open(self.path(name), mode))
  File "C:\Python27\lib\site-packages\django\core\files\storage.py", line 261, in path
    raise SuspiciousFileOperation("Attempted access to '%s' denied." % name)
django.core.exceptions.SuspiciousFileOperation: Attempted access to 'D:\Temp\importme\readme.html' denied.

full model can be found at GitHubfull command is currently on gist.github.com availableFileField

如果您不想查看模型:我的file课程的属性File为{{3}}。

我认为,这个问题发生了,因为我只是“链接”到找到的文件。但是我需要复制它,对吧?如何将文件复制到文件中?

4 个答案:

答案 0 :(得分:5)

分析stacktrace的这一部分:

File "C:\Python27\lib\site-packages\django\core\files\storage.py", line 261, in path
    raise SuspiciousFileOperation("Attempted access to '%s' denied." % name)

导致标准的Django FileSystemStorage。它希望文件在MEDIA_ROOT范围内。您的文件可以在文件系统中的任何位置,因此会出现此问题。

您应该传递类文件对象而不是File模型的路径。实现这一目标的最简单方法是使用Django File类,它是类似python文件的对象的包装器。有关详细信息,请参阅File object documentation

<强>更新

好的,我在这里建议从文档中获取路线:

from django.core.files import File as FileWrapper

def _handle_directory(self, directory_path, directory):
    for root, subFolders, files in os.walk(directory_path):
        for filename in files:
            self.cnt_files += 1
            new_file = File(
                 directory=directory, filename=filename,
                 file=os.path.join(root, filename),
                 uploader=self.uploader)
            with open(os.path.join(root, filename), 'r') as f:
                file_wrapper = FileWrapper(f)
                new_file = File(
                    directory=directory, filename=filename,
                    file=file_wrapper,
                    uploader=self.uploader)
                new_file.save()

如果有效,则应将文件复制到secure_storage可调用者提供的位置。

答案 1 :(得分:1)

在Django中,可以通过以下方式来避免SuspiciousFileOperation:从外部目录读取文件,并在项目媒体中制作一个tmp文件,然后将其保存在如下所示的适当文件中

import tempfile

file_name="file_name.pdf"
EXT_FILE_PATH = "/home/somepath/"
file_path = EXT_FILE_PATH + file_name
if exists(file_path):
    #create a named temporary file within the project base , here in media

    lf = tempfile.NamedTemporaryFile(dir='media')
    f = open(file_path, 'rb')
    lf.write(f.read())
    #doc object with file FileField.

    doc.file.save(file_name, File(lf), save=True)
    lf.close()

答案 2 :(得分:1)

我没有遇到类似的问题,但是相关的问题。我最近将Django 1.8升级到1.11。

现在,如果尝试在具有FileField字段的模型中保存文件,则会出现以下错误:

  

/ api / send_report /中的SuspiciousFileOperation   联接的路径(/vagrant/tmp/test_file.pdf)位于基本路径组件(/ vagrant / media)的外部

我要在其中保存文件的模型:

import random
sequence = []
def define_sequence():
    for i in range(0,100):
        sequence.append(random.randint(0,1))
    print(sequence)
return sequence
define_sequence()
def sequence_count():
    zero_count = 0 #counts the number of zeros so far
    max_zero_count = 0 #counts the maximum number of zeros seen so faz
    for i in sequence:
        if i == 0: #if i == 0 we increment both zero_count and max_zero_count
            zero_count += 1
            if zero_count > max_zero_count:
                max_zero_count = zero_count  #if the zero_count is more than the previous max_zero_count we assignt to max_zero_count the zero_count value
        else:
            zero_count = 0 #if i == 1 we reset the zero_count variable
    return max_zero_count
print(sequence_count())

我正在尝试按照以下代码从位于MEDIA_ROOT中的tmp文件夹中保存文件:

class Report(BaseModel):
    file = models.FileField(max_length=200, upload_to=os.path.join(settings.REPORTS_URL, '%Y/week_%W/'))
    type = models.CharField(max_length=20, verbose_name='Type', blank=False, default='', db_index=True)

我为解决该问题所做的事情:

from django.core.files import File

filepath = "/vagrant/tmp/test_file.pdf"
file = File(open(filepath, "rb"))
report_type = "My_report_type"
report = Report.objects.create(
    file=file,
    type=report_type,
)

希望它将对某人有所帮助。

答案 3 :(得分:0)

检查文件路径之前是否有斜杠

file_item = models.FileField(upload_to=content_file_name)


def content_file_name(username, filename):
    return '/'.join(['content', username, filename])

请注意"content"而不是"/content"。这对我来说是个问题。