【问题标题】:Turn off caching of static files in Django development server在 Django 开发服务器中关闭静态文件的缓存
【发布时间】:2011-10-24 05:34:16
【问题描述】:

有没有一种简单的方法可以在 Django 的开发服务器中关闭静态文件的缓存?

我正在使用标准命令启动服务器:

$ python manage.py runserver

我已将 settings.py 配置为从我的 Django 项目的 /static 目录中提供静态文件。我还有一个中间件类,它将Cache-Control 标头设置为must-revalidate, no-cache 以进行开发,但这似乎只会影响不在我的/static 目录中的URL。

【问题讨论】:

  • 将这种非缓存行为作为默认行为是this ticket 的主题,并被推迟等待可能与whitenoise 合并(这已经解决了这个问题)。
  • 您可以在incognito window 中测试您的网站。不会保存缓存。

标签: python django


【解决方案1】:

假设您使用的是django.views.static.serve,它看起来不像 - 但是编写您自己的视图来调用django.views.static.serve,添加 Cache-Control 标头应该相当容易。

【讨论】:

    【解决方案2】:

    @Erik Forsberg 的回答对我有用。这是我必须做的:

    • settings.py 中将INSTALLED_APPS 中的静态文件应用程序注释掉:

      INSTALLED_APPS = (
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.sites',
          'django.contrib.messages',
          #'django.contrib.staticfiles',
      )
      
    • 将我的STATIC_URL 变量集保留在settings.py 中:

      STATIC_URL = '/static/'
      
    • 在我的项目库中添加一个条目urls.py

      # static files w/ no-cache headers
      url(r'^static/(?P<path>.*)$', 'django.views.static.serve',
          {'document_root': settings.STATIC_ROOT}),
      

    请注意,我还在中间件类 nocache.py 中设置了 Cache-Control 标头:

    class NoCache(object):
        def process_response(self, request, response):
            """
            set the "Cache-Control" header to "must-revalidate, no-cache"
            """
            if request.path.startswith('/static/'):
                response['Cache-Control'] = 'must-revalidate, no-cache'
            return response
    

    然后将其包含在settings.py

    if DEBUG:
        MIDDLEWARE_CLASSES = (
            'django.middleware.common.CommonMiddleware',
            'django.contrib.sessions.middleware.SessionMiddleware',
            'django.middleware.csrf.CsrfViewMiddleware',
            'django.contrib.auth.middleware.AuthenticationMiddleware',
            'django.contrib.messages.middleware.MessageMiddleware',
            'nocache.NoCache',
        )
    

    【讨论】:

    • 您也可以在不禁用staticfiles 应用程序的情况下执行此操作,方法是使用--nostatic 选项启动runserver 命令。这将阻止staticfiles 应用程序提供静态文件。有关更多信息,请参阅我的答案。
    • 我看到这种方法的一个问题是,当模板文件中有 {% load staticfiles %} 时,一些应用程序(如“rest framework”)会中断。除此之外,它还解决了缓存问题
    • 奇怪的是,我无法让它工作。 Firefox/Chrome 似乎忽略了缓存控制,Django 没有发回正确的标头。我能找到的唯一解决方法是将随机数附加到媒体的 URL。
    • 对于应该开箱即用添加的东西来说相当复杂
    【解决方案3】:

    我非常简单的解决方案:

    from django.contrib.staticfiles.views import serve
    from django.views.decorators.cache import never_cache
    
    static_view = never_cache(serve)
    urlpatterns += static_view(settings.MEDIA_URL,
                               document_root=settings.MEDIA_ROOT)
    

    【讨论】:

    • 嗯。这对我不起作用。我收到此错误:TypeError: serve() takes at least 2 arguments (1 given)。也许您打算改用django.conf.urls.static?喜欢:urlpatterns = static(settings.STATIC_URL, view=never_cache(serve)) + urlpatterns
    【解决方案4】:

    Django 的contrib.staticfiles 应用程序通过覆盖runserver 命令自动为您提供静态文件。使用此配置,您无法控制它为静态文件提供服务的方式。

    您可以通过在 runserver 命令中添加 --nostatic 选项来阻止 staticfiles 应用提供静态文件:

    ./manage.py runserver --nostatic
    

    然后您可以编写一个 url 配置来手动提供带有标题的静态文件,以防止浏览器缓存响应:

    from django.conf import settings
    from django.contrib.staticfiles.views import serve as serve_static
    from django.views.decorators.cache import never_cache
    
    urlpatterns = patterns('', )
    
    if settings.DEBUG:
        urlpatterns += patterns('',
            url(r'^static/(?P<path>.*)$', never_cache(serve_static)),
        )
    

    如果您希望您的manage.py runserver 命令默认启用--nostatic 选项,您可以将其放入您的manage.py

    if '--nostatic' not in sys.argv:
        sys.argv.append('--nostatic')
    

    【讨论】:

    • 这是最简单的解决方法。
    • 似乎有点奇怪,这是必要的;在开发期间(根据建议您应该使用 runserver 的唯一时间)您真的不想缓存东西吗?在我看来,开发过程中的默认行为应该是 never_cache,并创建一个可选参数来打开 runserver 的缓存。意识到这不是 Django 建议的地方,但在研究这个主题时它让我印象深刻。
    • 这个答案并不总是有效。它可以被简化并使其更普遍有用。如果urlpatterns 在末尾包含一个包罗万象的 url,它将不起作用。所以将新的 url 添加到urlpatterns 的开头。如果您没有将STATIC_URL 设置为“静态”,它将无法正常工作。所以使用urlpatterns = static(settings.STATIC_URL, view=never_cache(serve_static)) + urlpatterns。 (static函数可以在django.conf.urls.static中找到。)
    • 某些manage.py 命令无法识别--nostatic 标志。更新 manage.py 以使用和更新 if sys.argv[1] == 'runserver' and '--nostatic' not in sys.argv: ... 的 if 语句似乎可以解决它。
    【解决方案5】:

    这与 Django 无关,因为在我使用 pip 重新安装 Django 后没有任何变化。

    这是浏览器的行为,所以你只需要清除浏览器缓存的图片文件。

    参考

    Chrome Clear cache and cookies

    【讨论】:

    • 是的,但你不想每隔几秒就这样做
    【解决方案6】:

    对于较新的 Django,中间件类的编写方式发生了一些变化。

    按照上面@aaronstacy 的所有说明进行操作,但对于中间件类,请使用:

    class NoCache(object):
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            response = self.get_response(request)
            response['Cache-Control'] = 'must-revalidate, no-cache'
            return response
    

    【讨论】:

      【解决方案7】:

      在较新版本的 Django 中,一个非常简单的解决方案是修改项目 url,如下所示:

      from django.conf.urls.static import static
      from django.contrib.staticfiles.views import serve
      from django.views.decorators.cache import cache_control
      from django.conf import settings
      
      # YOUR urlpatterns here... 
      
      if settings.DEBUG:
          urlpatterns += static(settings.STATIC_URL, view=cache_control(no_cache=True, must_revalidate=True)(serve))
      

      我通过查看 staticfiles 如何自动修改 url 并添加视图装饰器来实现这一点。我真的不明白为什么这不是默认设置,因为这仅用于开发。该视图能够正确处理“If-Modified-Since”HTTP 标头,因此始终发出请求,但内容仅在更改时传输(通过查看文件上的修改时间戳来判断)。

      为此,您必须在使用 runserver 时添加 --nostatic,否则上述更改将被忽略。

      重要编辑: 我之前的内容不起作用,因为我没有使用 --nostatic 并且 never_cache 装饰器还包含 no-store 这意味着始终会重新生成未更改的文件转移而不是返回304 Not Modified

      【讨论】:

        【解决方案8】:

        如果你使用的是 Django 2.0+,那就太简单了

        第 1 步:在 settings.py(项目级别)中将 'django.contrib.staticfiles' 作为注释

        INSTALLED_APPS = [

        # 'django.contrib.staticfiles',
        

        ]

        第 2 步:在 urls.py 中导入以下内容(项目级别)

             from django.conf.urls.static import static
        
             from django.contrib.staticfiles.views import serve
        
             from django.views.decorators.cache import never_cache
        
             from . import settings
        

        步骤3:在urlpatterns之后的urls.py(项目级别)中添加以下行

        urlpatterns = [
        
        ]
        
        if settings.DEBUG:
        
            urlpatterns += static(settings.STATIC_URL, view=never_cache(serve))
        

        确保在你的 settings.py 中声明了 STATIC_URL

        STATIC_URL = '/static/'
        

        【讨论】:

        • 这可以防止 Django 显示任何静态文件(图像、css 等)
        【解决方案9】:

        使用whitenoise。在 runserver 中提供的静态文件存在很多问题,它们都已在 whitenoise 中修复。它也更快。

        他们有talked about just replacing the built-in static serving with it,但还没有人处理它。

        在开发中使用它的步骤...

        使用pip install whitenoise安装

        在 settings.py 的末尾添加以下内容:

        if DEBUG:
            MIDDLEWARE = [
                'whitenoise.middleware.WhiteNoiseMiddleware',
            ] + MIDDLEWARE
            INSTALLED_APPS = [
                'whitenoise.runserver_nostatic',
            ] + INSTALLED_APPS
        

        【讨论】:

        • 10 年过去了,这仍然是一个问题。应该是最佳答案。
        【解决方案10】:

        staticfiles 应用通过overriding the runserver command 实现静态文件的服务。我们也可以这样做:再次覆盖此命令并实现一个自定义处理程序来关闭缓存。

        注意你的django应用必须在INSTALLED_APPS中的django.contrib.staticfiles之前,否则你的命令会被忽略。

        # your_django_app/management/commands/runserver.py
        
        from django.utils.cache import add_never_cache_headers
        from django.contrib.staticfiles.handlers import (
            StaticFilesHandler as BaseStaticFilesHandler,
        )
        from django.contrib.staticfiles.management.commands.runserver import (
            Command as RunserverCommand,
        )
        
        
        class StaticFilesHandler(BaseStaticFilesHandler):
            def serve(self, request):
                response = super().serve(request)
                add_never_cache_headers(response)
                return response
        
        
        class Command(RunserverCommand):
            def get_handler(self, *args, **options):
                handler = super().get_handler(*args, **options)
        
                # Check that serving static files is enabled
                if isinstance(handler, BaseStaticFilesHandler):
                    # If yes, replace the original handler with our custom handler
                    handler = StaticFilesHandler(handler.application)
        
                return handler
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-03-01
          • 2012-06-03
          • 1970-01-01
          • 2017-11-15
          • 1970-01-01
          • 2013-12-08
          • 2020-07-31
          • 2015-04-27
          相关资源
          最近更新 更多