Django - 来自图像的 SuspiciousFileOperation 添加到本地开发环境

Django - SuspiciousFileOperation from image add on local development environment

过去几个月我一直在开发基于 Django 的个人照片网站,并使用 AWS 成功部署了它。到目前为止,我已经在 Windows 10 桌面上完成了所有开发工作。我最近买了一台新的 Windows 10 笔记本电脑,但在设置开发环境时遇到了困难。我将我的 Github 存储库克隆到我的笔记本电脑上,并成功地将网站 运行 本地化。但是,当我转到管理页面上传照片时,每次我都会收到 SuspiciousFileOperation 异常。加入的路径位于基本路径组件之外。当 运行ning collectstatic 时,我也遇到了这个错误。这些设置与我的桌面设置相同,除非我忽略了一个正盯着我看的问题。

我认为这可能与我设置 virtualenv 的方式或我的 MEDIA 变量的设置方式有关,尽管它们与我桌面上的工作方式相同。我已经通读了 Django 文档,但没有找到任何确定的内容。或者也许有人可以解释更多关于设置 virtualenv 的信息? Django/Python 是否需要我错过在笔记本电脑上设置的某些权限来移动文件?

下面是完整的错误和相关的代码片段。

堆栈跟踪:

    Environment:


    Request Method: POST
    Request URL: http://127.0.0.1:8000/admin/PortfolioApp/image/add/

    Django Version: 2.1.4
    Python Version: 3.7.1
    Installed Applications:
    ['django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'PortfolioApp.apps.PortfolioappConfig',
     'storages']
    Installed Middleware:
    ['django.middleware.security.SecurityMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware']



    Traceback:

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\core\handlers\exception.py" in inner
      34.             response = get_response(request)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\core\handlers\base.py" in _get_response
      126.                 response = self.process_exception_by_middleware(e, request)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\core\handlers\base.py" in _get_response
      124.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\contrib\admin\options.py" in wrapper
      604.                 return self.admin_site.admin_view(view)(*args, **kwargs)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\utils\decorators.py" in _wrapped_view
      142.                     response = view_func(request, *args, **kwargs)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
      44.         response = view_func(request, *args, **kwargs)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\contrib\admin\sites.py" in inner
      223.             return view(request, *args, **kwargs)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\contrib\admin\options.py" in add_view
      1637.         return self.changeform_view(request, None, form_url, extra_context)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\utils\decorators.py" in _wrapper
      45.         return bound_method(*args, **kwargs)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\utils\decorators.py" in _wrapped_view
      142.                     response = view_func(request, *args, **kwargs)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\contrib\admin\options.py" in changeform_view
      1525.             return self._changeform_view(request, object_id, form_url, extra_context)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\contrib\admin\options.py" in _changeform_view
      1564.                 self.save_model(request, new_object, form, not add)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\contrib\admin\options.py" in save_model
      1091.         obj.save()

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\base.py" in save
      718.                        force_update=force_update, update_fields=update_fields)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\base.py" in save_base
      748.             updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\base.py" in _save_table
      831.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\base.py" in _do_insert
      869.                                using=using, raw=raw)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\manager.py" in manager_method
      82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\query.py" in _insert
      1136.         return query.get_compiler(using=using).execute_sql(return_id)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql
      1288.             for sql, params in self.as_sql():

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\sql\compiler.py" in as_sql
      1241.                 for obj in self.query.objs

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\sql\compiler.py" in <listcomp>
      1241.                 for obj in self.query.objs

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\sql\compiler.py" in <listcomp>
      1240.                 [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\sql\compiler.py" in pre_save_val
      1192.         return field.pre_save(obj, add=True)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\fields\files.py" in pre_save
      288.             file.save(file.name, file.file, save=False)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\db\models\fields\files.py" in save
      87.         self.name = self.storage.save(name, content, max_length=self.field.max_length)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\core\files\storage.py" in save
      48.         name = self.get_available_name(name, max_length=max_length)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\core\files\storage.py" in get_available_name
      72.         while self.exists(name) or (max_length and len(name) > max_length):

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\core\files\storage.py" in exists
      308.         return os.path.exists(self.path(name))

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\core\files\storage.py" in path
      321.         return safe_join(self.location, name)

    File "C:\Users\Bryan\Envs\dj\lib\site-packages\django\utils\_os.py" in safe_join
      49.             'component ({})'.format(final_path, base_path))

    Exception Type: SuspiciousFileOperation at /admin/PortfolioApp/image/add/
    Exception Value: The joined path (C:\Users\Bryan\Documents\GitHub\Portfolio\media\pictures\VeselkaNYC-BJM.jpg) is located outside of the base path component (C:\Users\Bryan\Documents\GitHub\Portfolio\media\)

models.py

    class Image(models.Model):
        ...
        picture = models.ImageField(upload_to='pictures/', height_field='height', width_field='width', null=True)
        ...

settings.py

    ...
    STATIC_URL = '/static/'
    STATIC_ROOT = 'static/'

    MEDIA_URL = '/media/'
    MEDIA_ROOT = 'media/'
    ...

urls.py

    ...
    if settings.DEBUG:
        # Use static() to add url mapping to serve static files during development (only)
        urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
        urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

我已经包含了我认为相关的代码片段,但请询问您是否需要更多帮助我。非常感谢任何帮助。

编辑: 感谢 Giancarlo 的建议,重新定义了我的 STATIC_ROOT 和 MEDIA_ROOT 如下:

    STATIC_ROOT = os.join.path(BASE_DIR, "static")
    MEDIA_ROOT = os.join.path(BASE_DIR, "media")

我认为我桌面上的设置之所以有效,是因为 .pyc 缓存文件包含在开发过程中保存的正确设置。这是我能想到的最好的。

将您的 STATIC_ROOT 和 MEDIA_ROOT 更改为

STATIC_ROOT = os.path.join(BASE_DIR, "static/")
MEDIA_ROOT = os.path.join(BASE_DIR, "media/")

因为 Windows 可能正在 C:\mediaC:\static

搜索

编辑:我认为 BASE_DIR 是在 settings.py 中预定义的,但这里是如果它丢失了

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

并且可以肯定的是,在 upload_to

后面添加一个斜线
upload_to='pictures/'