将 Django CMS 添加到我的项目后,管理命令因缓存错误而失败。我该如何解决?

After adding Django CMS to my project, management commands fail with a cache error. How can I fix it?

这是使用 Django 1.7 和 Django CMS 3.1.0。

我有一个大型 Django 项目,该项目已经投入生产几个月没有任何问题。我目前正在向其中添加 Django CMS,发现如果我的缓存处于脱机状态,我将无法发出任何管理命令而不会出现异常。 在我将 Django CMS 添加到我的项目之前,它曾经工作得很好。

这可以通过以下方式复制:

  1. 按照 documentation.

  2. 中的说明手动安装 Django CMS
  3. 设置连接到可以脱机的缓存服务的默认缓存。在我的例子中,我连接到一个仅供我的 Django 项目使用的 Redis 服务器。该服务器是在我 运行 manage.py runserver 开发之前和我的 Web 应用程序在生产环境中联机之前手动启动的。打开缓存服务可以解决问题,但有时我想 运行 在关闭缓存服务的情况下执行一些管理命令。

如果我在我的 Redis 实例离线时 运行 任何管理命令,我都会失败。例如,如果我只是 运行 ./manage.py 而没有命令,我会得到这样的跟踪:

Traceback (most recent call last):
  File "./manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  File "env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute
    django.setup()
  File "env/local/lib/python2.7/site-packages/django/__init__.py", line 21, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "env/local/lib/python2.7/site-packages/django/apps/registry.py", line 115, in populate
    app_config.ready()
  File "env/local/lib/python2.7/site-packages/django/contrib/admin/apps.py", line 22, in ready
    self.module.autodiscover()
  File "env/local/lib/python2.7/site-packages/django/contrib/admin/__init__.py", line 23, in autodiscover
    autodiscover_modules('admin', register_to=site)
  File "env/local/lib/python2.7/site-packages/django/utils/module_loading.py", line 74, in autodiscover_modules
    import_module('%s.%s' % (app_config.name, module_to_search))
  File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
  File "env/local/lib/python2.7/site-packages/cms/admin/__init__.py", line 11, in <module>
    plugin_pool.plugin_pool.discover_plugins()
  File "env/local/lib/python2.7/site-packages/cms/plugin_pool.py", line 33, in discover_plugins
    invalidate_cms_page_cache()
  File "env/local/lib/python2.7/site-packages/cms/views.py", line 335, in invalidate_cms_page_cache
    version = _get_cache_version()
  File "env/local/lib/python2.7/site-packages/cms/views.py", line 280, in _get_cache_version
    version = cache.get(CMS_PAGE_CACHE_VERSION_KEY)
  File "env/local/lib/python2.7/site-packages/django_redis/cache.py", line 30, in _decorator
    raise e.parent
redis.exceptions.ConnectionError: Error 2 connecting to unix socket: /var/tmp/foo/redis/foo_dev.redis.sock. No such file or directory.

如果我只是从 INSTALLED_APPS 中删除 cms 应用程序,这足以防止出现问题,但这不是一个可接受的修复方法。

有没有一种方法可以在不删除 Django CMS 或在发出任何管理命令之前打开缓存服务的情况下修复此问题?

问题

对于 Django 1.7 和 1.8 以及可预见的未来版本,该问题是相同的。 1.6 和更早版本并非不可能发生,但不太可能。

问题是,如果您使用最有可能用于 Django 项目的配置,那么每当初始化 cms 应用程序时,Django CMS 都会导致对缓存的访问。

以下是当您 运行 管理命令时发生的情况,省略了一些不相关的步骤:

  1. Django 完成应用程序初始化过程。 (已记录 here。)当它到达 django.contrib.admin 时,它使用此应用程序的默认值 AppConfig

  2. admin 的默认 AppConfig 调用 adminautodiscover() 函数。 (记录here。)

  3. 最终 autodiscover() 获取 cms 自己的 admin.py 文件,并加载它。该文件启动 Django CMS 插件的发现,这反过来导致 Django CMS 使其页面缓存无效。所以你在那里获得了一个缓存访问,但是失败了,因为你的缓存服务没有打开。

解决方案

你可以做的是,正如关于管理员 explains 的文档,在你的 INSTALLED_APPS 中使用 django.contrib.admin.apps.SimpleAdminConfig 而不是 django.contrib.admin。此应用程序配置不会自动调用 autodiscover()。当你使用这个配置时,那么你必须自己调用autodiscover()。在您的项目范围内进行调用 urls.py,就像我们在 1.7 之前被要求做的那样,是您最好的选择:

from django.contrib import admin
admin.autodiscover()

以上应该清楚地表明 OP 的问题不太可能发生在 1.6 之前的 Django 版本中。按照 Django 的文档配置他们的项目的人会在他们的 urls.py 文件中调用 autodiscover(),该文件只在进行网络查询时才被读取。然而,问题 可以 发生在那些偏离推荐做法并最终在其他地方调用 autodiscover() 的项目的人身上。