【问题标题】:django-storages dropbox.stone_validators.ValidationErrordjango-storages dropbox.stone_validators.ValidationError
【发布时间】:2019-08-30 09:49:22
【问题描述】:

我正在尝试将保管箱用作媒体存储。我正在尝试通过 django-storages 来实现。

settings.py

DEFAULT_FILE_STORAGE = 'storages.backends.dropbox.DropBoxStorage'
DROPBOX_OAUTH2_TOKEN = 'token'
DROPBOX_ROOT_PATH = '/media/'

models.py

logo = models.ImageField(upload_to=r'logo/%Y/%m/')
image = models.ImageField(upload_to=r'photos/%Y/%m/',
 help_text='Image size: Width=1080 pixel. Height=1920 pixel',)

错误

请求方法:|发布

请求网址:| http://127.0.0.1:8000/add

Django 版本:| 2.1.8

异常类型:|验证错误

异常值:| 'D:/media/10506738_10150004552801856_220367501106153455_o.jpg' 不匹配模式 '(/(.|[\r\n])|id:.)|(rev:[0-9a-f]{9,})|( ns:[0-9]+(/.*)?)'

控制台

dropbox.stone_validators.ValidationError: 'D:/media/10506738_10150004552801856_220367501106153455_o.jpg' 不匹配模式 '(/(.|[\r\n])|id:.)|(rev:[0-9a- f]{9,})|(ns:[0-9]+(/.*)?)'

我不知道为什么会发生这个错误?

【问题讨论】:

    标签: python mysql json django dropbox


    【解决方案1】:

    此错误消息来自 Dropbox API,表明为 Dropbox API 调用提供的“路径”不具有预期的格式。例如,如果您要上传文件,您提供的“路径”将是您要放置上传数据的 Dropbox 帐户中的路径。

    您正在提供价值:

    D:/media/10506738_10150004552801856_220367501106153455_o.jpg

    (这似乎是本地 Windows 文件系统路径。)

    您提供的 Dropbox 路径应该类似于:

    /media/10506738_10150004552801856_220367501106153455_o.jpg

    (这将是相对于 Dropbox 根目录的路径。它没有驱动器号。)

    您需要深入研究您的代码,以查看向 Dropbox 提供不正确路径类型的位置/原因。

    【讨论】:

      【解决方案2】:

      问题出在 Windows 操作系统路径上。我尝试在 Ubuntu 中使用相同的设置。它在那里完美地工作。

      【讨论】:

        【解决方案3】:

        关于为什么会发生此错误,其他答案并不完全正确。 Dropbox 存储对象后端使用 django 实用程序(django.utils._os.safe_join) 来验证目标操作系统的文件名。见代码here

        即使你传递了upload_to 参数,它给出了一个 unix 风格的路径(类似于 /save/path),django 实用程序确保该保存路径的根与操作系统的基本路径匹配:(。 dropbox SDK 不喜欢以所需保存路径为前缀的驱动器(AKA C:/path/file.name 不是 dropbox 的有效保存目录)。

        要使这项工作在 Windows 上运行,请确保您做几件事

        首先,像这样修改存储后端_full_path方法(或创建自己的子类)。

        def _full_path(self, name):
            if name == '/':
                name = ''
            print('Root path in dropbox.storage : ', self.root_path)
        
            # If the machine is windows do not append the drive letter to file path
            if os.name == 'nt':
                final_path = os.path.join(self.root_path, name).replace('\\', '/')
        
                # Separator on linux system
                sep = '//'
                base_path = self.root_path
        
                if (not os.path.normcase(final_path).startswith(os.path.normcase(base_path + sep)) and
                        os.path.normcase(final_path) != os.path.normcase(base_path) and
                        os.path.dirname(os.path.normcase(base_path)) != os.path.normcase(base_path)):
                    raise SuspiciousFileOperation(
                        'The joined path ({}) is located outside of the base path '
                        'component ({})'.format(final_path, base_path))
                # TODO Testing
                print('Full file path in storage.dropbox._full_path : ', final_path)
                return final_path
        
            else:
                return safe_join(self.root_path, name).replace('\\', '/')
        

        其次,确保将内容和名称传递给模型 FileField。当我没有明确传递文件内容和名称时(关于上传的文件上下文保留文件名的问题?),我遇到了麻烦。我像这样重新实现了我的模型保存方法

        def save(self, *args, **kwargs):
            # Save file
        
            ## Save raw entry from user ##
            # Extract files contents
            try:
                uploaded_raw_entry = kwargs['upload_raw_entry']
            except KeyError:
                raise UploadError(('No file was passed from the admin interface. ' + 
                    'Make sure a ContentFile was passed when calling this models save method'))
        
            # Test raw_directory_path TODO Remove after testing
            print('Raw entry name from model.save : ', raw_directory_path(self, uploaded_raw_entry.name))
        
            with uploaded_raw_entry.open(mode='rb') as f:
                raw_entry_content = f.read()
            raw_entry_file = ContentFile(content=raw_entry_content.encode('utf-8'),
                                         name=raw_directory_path(self, uploaded_raw_entry.name))
        
            # Save the content file into a model field
            raw_entry_file.open(mode='rb')
            self.raw_entry.save(raw_entry_file.name, raw_entry_file, save=False)
            raw_entry_file.close()
        

        这绝对可以在 Windows 上使用,但需要额外的步骤 :)

        【讨论】:

          【解决方案4】:

          我也在我的 Linux 工作站上遇到了这个问题 - 所以@greg 的答案的等效 Linux 答案是在您的备份名称中添加一个 "/":

          import sys, os
          import dropbox
          from dropbox.files import WriteMode
          from dropbox.exceptions import ApiError, AuthError
          
          # Add OAuth2 access token here.
          TOKEN = '<your-token>'
          
          data_path = './data_files'
          filename   = 'my-file-backup.txt'
          BACKUPPATH = "/"+filename  # <----- This should do the trick!
          
          # Uploads contents of filename to Dropbox
          def backup():
              current_file_path = os.path.join(data_path, filename)
              with open(current_file_path, 'rb') as f:
                  print("Uploading " + filename + " to Dropbox as " + BACKUPPATH + "...")
                  try:
                      dbx.files_upload(f.read(), BACKUPPATH, mode=WriteMode('overwrite'))
                  except ApiError as err:
                      if (err.error.is_path() and
                              err.error.get_path().reason.is_insufficient_space()):
                          sys.exit("ERROR: Cannot back up; insufficient space.")
                      elif err.user_message_text:
                          print(err.user_message_text)
                          sys.exit()
                      else:
                          print(err)
                          sys.exit()
          

          因此,错误消息非常令人困惑 - 有问题的文件名和路径不是您的本地文件名和路径,而是 Dropbox 远程文件名和路径。

          【讨论】:

            猜你喜欢
            • 2020-03-26
            • 2014-12-31
            • 2020-05-27
            • 2012-05-01
            • 1970-01-01
            • 2014-06-06
            • 1970-01-01
            • 1970-01-01
            • 2016-06-20
            相关资源
            最近更新 更多