我正在使用django 1.10构建一个网站。我编写了一个中间件类来限制未登录用户的页面查看次数。我将此功能实现到一个单独的应用程序' pagerestrict'
settings.py [相关条目]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'pagerestrict.apps.PagerestrictConfig',
# ...
]
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',
'pagerestrict.middleware.CheckPageAccessMiddleware',
]
中间件代码(middleware.py):
from django.http import HttpResponseRedirect
from decouple import config
class CheckPageAccessMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_request(self, request):
if not request.user.is_authenticated():
current_page_url = request.path_info.lstrip('/')
ignore_list = config('PAGE_RESTRICT_PAGE_IGNORES', cast=lambda v: [s.strip() for s in v.split(',')])
#if not current_page_url or not any(current_page_url != url for url in ignore_list):
if not current_page_url in ignore_list:
# first things first ...
if not has_attr(request, 'pages_visited'):
request.pages_visited = set()
if not has_attr(request, 'page_count'):
request.page_count = 0
if current_page_url not in request.pages_visited:
request.pages_visited.add(current_page_url)
request.page_count += 1
if request.page_count > config('PAGE_RESTRICT_PAGE_LIMIT'):
return HttpResponseRedirect(config('PAGE_RESTRICT_REDIRECT_URL'))
我通过访问我的主页并多次刷新浏览器来测试这一点 - 代码似乎永远不会被触发。我错过了什么?
答案 0 :(得分:8)
默认情况下,新式中间件不会调用process_request
和process_response
。此功能已替换为__call__
和传递给get_response
的{{1}}函数。
您需要在__init__
内调用process_request()
并处理返回值,如果它不是__call__
。最简单的方法是使用Django提供的None
。这将定义必要的MiddlewareMixin
和__init__
方法,__call__
将调用__call__
和process_request()
(如果已定义)。
process_response()
答案 1 :(得分:4)
我终于开始工作了。它基于现已解散的Stack Overflow Documentation站点上的Middleware主题。 (可以在contributor page上找到归因详细信息。参考主题ID:1721。)
from django.http import HttpResponseRedirect
from decouple import config
class CheckPageAccessMiddleware(object):
def __init__(self, next_layer=None):
"""We allow next_layer to be None because old-style middlewares
won't accept any argument.
"""
self.get_response = next_layer
def process_request(self, request):
"""Let's handle old-style request processing here, as usual."""
# Do something with request
# Probably return None
# Or return an HttpResponse in some cases
if not request.user.is_authenticated():
current_page_url = request.path_info.lstrip('/')
print ('Current page url: {0}'.format(current_page_url))
root_url = '' # root url == ('')
restrict_redirect_page = config('PAGE_RESTRICT_REDIRECT_URL')[1:] # chop of leading '/'
ignore_list = [root_url, restrict_redirect_page] + \
config('PAGE_RESTRICT_PAGE_IGNORES', cast=lambda v: [s.strip() for s in v.split(',')])
print('ignore list: %s' % ",".join([x for x in ignore_list]))
#if not current_page_url or not any(current_page_url != url for url in ignore_list):
if not current_page_url in ignore_list:
# first things first ...
if 'pages_visited' not in request.session:
request.session['pages_visited'] = ''
if 'page_count' not in request.session:
request.session['page_count'] = 0
pages_visited = [x.strip() for x in request.session['pages_visited'].split(',')]
if current_page_url not in pages_visited:
pages_visited.append(current_page_url)
request.session['pages_visited'] = ",".join(x.strip() for x in pages_visited)
request.session['page_count'] += 1
print('Request page count: {0}'.format(request.session['page_count']))
if request.session['page_count'] > config('PAGE_RESTRICT_PAGE_LIMIT', cast=int):
return HttpResponseRedirect(config('PAGE_RESTRICT_REDIRECT_URL'))
return None
def process_response(self, request, response):
"""Let's handle old-style response processing here, as usual."""
# Do something with response, possibly using request.
return response
def __call__(self, request):
"""Handle new-style middleware here."""
response = self.process_request(request)
if response is None:
# If process_request returned None, we must call the next middleware or
# the view. Note that here, we are sure that self.get_response is not
# None because this method is executed only in new-style middlewares.
response = self.get_response(request)
response = self.process_response(request, response)
return response
答案 2 :(得分:1)
您可以像这样更改导入:
try:
from django.utils.deprecation import MiddlewareMixin
except ImportError:
MiddlewareMixin = object
答案 3 :(得分:0)
新型中间件默认情况下不会调用process_request和process_response。 此功能已由 call 和get_response函数取代, 传递给 init 。N您需要在调用中调用process_request(),然后 如果返回值不是None,则处理返回值。 因此,您可以将要放入process_request()方法中的代码编写为调用(),如下所示:
from django.http import HttpResponseRedirect
from decouple import config
class CheckPageAccessMiddleware(object):
def __init__(self, next_layer=None):
self.get_response = next_layer
def __call__(self, request):
if not request.user.is_authenticated():
current_page_url = request.path_info.lstrip('/')
ignore_list = config('PAGE_RESTRICT_PAGE_IGNORES', cast=lambda v: [s.strip() for s in v.split(',')])
#if not current_page_url or not any(current_page_url != url for url in ignore_list):
if not current_page_url in ignore_list:
# first things first ...
if not has_attr(request, 'pages_visited'):
request.pages_visited = set()
if not has_attr(request, 'page_count'):
request.page_count = 0
if current_page_url not in request.pages_visited:
request.pages_visited.add(current_page_url)
request.page_count += 1
if request.page_count > config('PAGE_RESTRICT_PAGE_LIMIT'):
return HttpResponseRedirect(config('PAGE_RESTRICT_REDIRECT_URL'))
答案 4 :(得分:0)
这里是一个示例,展示了如何在迁移到中间件时更新中间件
Django ver > 1.10
:
Upgrading pre-Django 1.10-style middleware
如果它不起作用:
您还应该暂时删除所有default MIDDLEWARE class
,
仅保留your custom MIDDLEWARE
以确保前一个
层(default MIDDLEWARE
)并未中断流程:
MIDDLEWARE = (
# 'django.middleware.common.CommonMiddleware',
'app.middleware.MyMiddlewareClass',
)
django.middleware.common.CommonMiddleware
,它将起作用。那可能是ALLOWED_HOSTS
问题。 - Replace
ALLOWED_HOSTS= ['localhost:8001']
- With
ALLOWED_HOSTS= ['localhost']