Django:如何从会话创建中排除视图?
Django: How to exclude a View from session creation?
我的 Django 项目严重依赖会话,框架在这方面做得很好。它管理会话 Cookie、会话数据库等,主要通过会话中间件完成。
但是有些视图明确不需要会话。这些视图通常显示为页面的条目。
我可以从创建新会话的 SessionMiddleware 中排除这些视图吗?如果一个新的(匿名)用户访问这样的视图并离开,则无需在会话中设置 Cookie 或创建数据库记录 table.
我采用了 "Adapt the Middleware" 方式,因为看起来会话仅在访问会话时创建,或者在全新会话的情况下在处理 SessionMiddleware 中的响应期间创建。
所以我创建了这个中间件,它扩展了 SessionMiddleware
:
from django.contrib.sessions.middleware import SessionMiddleware
from django.http import HttpRequest
class ConditionalSessionMiddleware(SessionMiddleware):
def process_request(self, request: HttpRequest):
# Default: We need a Session
setattr(request, '_conditional_session_middleware_session_required', True)
return super(ConditionalSessionMiddleware, self).process_request(request)
def process_response(self, request: HttpRequest, response):
# Is still a Session required?
required = getattr(request, '_conditional_session_middleware_session_required', True)
# or is the user not anonymous?
if required or not request.user.is_anonymous:
return super(ConditionalSessionMiddleware, self).process_response(request, response)
else:
return response
为了使用它,我创建了一个简单的函数装饰器:
from types import MethodType
class NoSessionUsed:
def __init__(self, f):
self.__func = f
def __call__(self, *args, **kwargs):
for a in args:
if isinstance(a, HttpRequest):
setattr(a, '_conditional_session_middleware_session_required', False)
break
return self.__func(*args, **kwargs)
def __get__(self, instance, owner):
if instance:
return MethodType(self, instance)
else:
return self
在基于 class 的视图中,我在 dispatch
方法上使用装饰器:
@NoSessionUsed
def dispatch(self, request, *args, **kwargs):
return super(MyClassBasedView, self).dispatch(request, *args, **kwargs)
您也可以在 urls.py 中使用它,例如对于 Sitemaps 和 Feed,您无法直接访问视图:
urlpatterns = [
path('rss.xml', NoSessionUsed(RssFeed()), name='rss'),
path('atom.xml', NoSessionUsed(AtomFeed()), name='atom'),
path('sitemap.xml', NoSessionUsed(views.index), {
'sitemaps': SITEMAPS,
'sitemap_url_name': 'sitemaps:sitemap.section'
}, name='sitemap'),
path('sitemaps/sitemap-<section>.xml', NoSessionUsed(views.sitemap), {
'sitemaps': SITEMAPS
}, name='sitemap.section'),
]
为了激活新的中间件,我用新的 ConditionalSessionMiddleware
.
替换了 settings.py MIDDLEWARE
部分中的 SessionMiddleware
当然也有缺点:
- 当我在装饰视图中使用会话时,更改很可能不会被保存
- 当我在修饰视图中使用新会话时,用户将不会获得会话 Cookie
这可能不是完美的解决方案,但它非常简单并且适合我。
我的 Django 项目严重依赖会话,框架在这方面做得很好。它管理会话 Cookie、会话数据库等,主要通过会话中间件完成。
但是有些视图明确不需要会话。这些视图通常显示为页面的条目。
我可以从创建新会话的 SessionMiddleware 中排除这些视图吗?如果一个新的(匿名)用户访问这样的视图并离开,则无需在会话中设置 Cookie 或创建数据库记录 table.
我采用了 "Adapt the Middleware" 方式,因为看起来会话仅在访问会话时创建,或者在全新会话的情况下在处理 SessionMiddleware 中的响应期间创建。
所以我创建了这个中间件,它扩展了 SessionMiddleware
:
from django.contrib.sessions.middleware import SessionMiddleware
from django.http import HttpRequest
class ConditionalSessionMiddleware(SessionMiddleware):
def process_request(self, request: HttpRequest):
# Default: We need a Session
setattr(request, '_conditional_session_middleware_session_required', True)
return super(ConditionalSessionMiddleware, self).process_request(request)
def process_response(self, request: HttpRequest, response):
# Is still a Session required?
required = getattr(request, '_conditional_session_middleware_session_required', True)
# or is the user not anonymous?
if required or not request.user.is_anonymous:
return super(ConditionalSessionMiddleware, self).process_response(request, response)
else:
return response
为了使用它,我创建了一个简单的函数装饰器:
from types import MethodType
class NoSessionUsed:
def __init__(self, f):
self.__func = f
def __call__(self, *args, **kwargs):
for a in args:
if isinstance(a, HttpRequest):
setattr(a, '_conditional_session_middleware_session_required', False)
break
return self.__func(*args, **kwargs)
def __get__(self, instance, owner):
if instance:
return MethodType(self, instance)
else:
return self
在基于 class 的视图中,我在 dispatch
方法上使用装饰器:
@NoSessionUsed
def dispatch(self, request, *args, **kwargs):
return super(MyClassBasedView, self).dispatch(request, *args, **kwargs)
您也可以在 urls.py 中使用它,例如对于 Sitemaps 和 Feed,您无法直接访问视图:
urlpatterns = [
path('rss.xml', NoSessionUsed(RssFeed()), name='rss'),
path('atom.xml', NoSessionUsed(AtomFeed()), name='atom'),
path('sitemap.xml', NoSessionUsed(views.index), {
'sitemaps': SITEMAPS,
'sitemap_url_name': 'sitemaps:sitemap.section'
}, name='sitemap'),
path('sitemaps/sitemap-<section>.xml', NoSessionUsed(views.sitemap), {
'sitemaps': SITEMAPS
}, name='sitemap.section'),
]
为了激活新的中间件,我用新的 ConditionalSessionMiddleware
.
MIDDLEWARE
部分中的 SessionMiddleware
当然也有缺点:
- 当我在装饰视图中使用会话时,更改很可能不会被保存
- 当我在修饰视图中使用新会话时,用户将不会获得会话 Cookie
这可能不是完美的解决方案,但它非常简单并且适合我。