Django:如何从会话创建中排除视图?
我的Django项目严重依赖于会话,框架在这方面做得非常好。它主要通过SessionMiddleware管理会话cookie、会话数据库等 但是有一些视图明确地不需要会话。这些视图通常显示为页面的一个条目 我可以从创建新会话的SessionMiddleware中排除这些视图吗?如果新(匿名)用户访问此类视图并离开,则无需在会话表中设置Cookie或创建数据库记录。我采用了“调整中间件”的方式,因为看起来只有在访问会话时才创建会话,或者在SessionMiddleware中处理响应时(如果是全新的会话) 所以我创建了这个中间件,它扩展了Django:如何从会话创建中排除视图?,django,django-views,django-sessions,Django,Django Views,Django Sessions,我的Django项目严重依赖于会话,框架在这方面做得非常好。它主要通过SessionMiddleware管理会话cookie、会话数据库等 但是有一些视图明确地不需要会话。这些视图通常显示为页面的一个条目 我可以从创建新会话的SessionMiddleware中排除这些视图吗?如果新(匿名)用户访问此类视图并离开,则无需在会话表中设置Cookie或创建数据库记录。我采用了“调整中间件”的方式,因为看起来只有在访问会话时才创建会话,或者在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
在基于类的视图中,我在dispatch
方法上使用decorator:
@NoSessionUsed
def dispatch(self, request, *args, **kwargs):
return super(MyClassBasedView, self).dispatch(request, *args, **kwargs)
您也可以在URL.py中使用它,例如,对于无法直接访问视图的站点地图和提要:
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'),
]
urlpatterns=[
path('rss.xml',NoSessionUsed(RssFeed()),name='rss'),
path('atom.xml',NoSessionUsed(AtomFeed()),name='atom'),
使用的路径('sitemap.xml')(views.index){
“站点地图”:站点地图,
“站点地图url\u名称”:“站点地图:站点地图.section”
},name='sitemap'),
路径('sitemaps/sitemap-.xml',已使用(views.sitemap){
“站点地图”:站点地图
},name='sitemap.section'),
]
为了激活新的中间件,我将settings.pyMiddleware
部分中的SessionMiddleware
替换为新的ConditionalSessionMiddleware
当然也有不利因素:
- 在装饰视图中使用会话时,更改很可能不会保存
- 当我在装饰视图中使用新会话时,用户将不会获得会话Cookie
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
在基于类的视图中,我在dispatch
方法上使用decorator:
@NoSessionUsed
def dispatch(self, request, *args, **kwargs):
return super(MyClassBasedView, self).dispatch(request, *args, **kwargs)
您也可以在URL.py中使用它,例如,对于无法直接访问视图的站点地图和提要:
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'),
]
urlpatterns=[
path('rss.xml',NoSessionUsed(RssFeed()),name='rss'),
path('atom.xml',NoSessionUsed(AtomFeed()),name='atom'),
使用的路径('sitemap.xml')(views.index){
“站点地图”:站点地图,
“站点地图url\u名称”:“站点地图:站点地图.section”
},name='sitemap'),
路径('sitemaps/sitemap-.xml',已使用(views.sitemap){
“站点地图”:站点地图
},name='sitemap.section'),
]
为了激活新的中间件,我将settings.pyMiddleware
部分中的SessionMiddleware
替换为新的ConditionalSessionMiddleware
当然也有不利因素:
- 在装饰视图中使用会话时,更改很可能不会保存
- 当我在装饰视图中使用新会话时,用户将不会获得会话Cookie
这可能不是一个完美的解决方案,但它非常简单,对我来说很有效。访问此类视图的用户是经过身份验证的用户还是匿名用户?@AKS:会话只会为匿名用户创建。一个经过身份验证的用户已经有了一个会话,所以我不在乎是否由于视图的访问而设置了cookie。但是对于匿名用户,我不希望有新会话。您可以扩展
SessionMiddleware
并覆盖process\u请求
和process\u响应
,以匹配您的用例。在这里,您可以比较视图名称并提前返回,而无需进行处理。然后在“设置”中,用您自己的会话中间件替换会话中间件。@AKS:已经想到了,但希望有一种更简单的、配置或注释驱动的方法。我不确定是否有这种方法查看源代码。因此,如果您想更改该行为,我认为您必须扩展该类。访问此类视图的用户是经过身份验证的用户还是匿名用户?@AKS:将仅为匿名用户创建会话。一个经过身份验证的用户已经有了一个会话,所以我不在乎是否由于视图的访问而设置了cookie。但是对于匿名用户,我不希望有新会话。您可以扩展SessionMiddleware
并覆盖process\u请求
和process\u响应
,以匹配您的用例。在这里,您可以比较视图名称并提前返回,而无需进行处理。然后在“设置”中,用您自己的会话中间件替换会话中间件。@AKS:已经想到了,但希望有一种更简单的、配置或注释驱动的方法。我不确定是否有这种方法查看源代码。所以如果你想改变行为,我认为你必须扩展这个类。