这是一个相当古老的问题,但今天仍然存在需求。
根据先前答案中提供的提示,我为基于类的视图制作了以下 mixin:
from urllib.parse import urlparse, urlencode
from django.http import QueryDict, HttpRequest
from django.contrib.auth.mixins import AccessMixin
class loginRequiredOnPostMixin (AccessMixin):
"""
Lets a CBV be freely accessible on GET requests, but requires login on POST.
On redirect for unauthenticated POST requests, the POST parameters are stored in the session.
Once the user authenticated and is redirected to the page as GET, the POST parameters are retrieved so the request can complete.
"""
SESSION_REFERER_KEY = None
SESSION_POST_PARAMS_KEY = None
def get_session_referer_key(self):
return self.SESSION_REFERER_KEY or 'POST_REDIRECT_REFERER'
def get_session_post_params_key(self):
return self.SESSION_POST_PARAMS_KEY or 'POST_PARAMS'
def dispatch(self, request, *args, **kwargs):
referer_key = self.get_session_referer_key()
post_params_key = self.get_session_post_params_key()
if request.method == 'POST' and bool(request.POST) and not request.user.is_authenticated:
# save the referer url to match it later in case of GET to the same page (after login)
if not request.session.has_key(referer_key): # so we don't overwrite previous values)
parsed_url = urlparse(request.META.get('HTTP_REFERER'))
request.session[referer_key] = parsed_url.path
# save the POST params in the session
request.session[post_params_key] = request.POST
#redirect to login View
return self.handle_no_permission()
elif request.method == 'POST' and request.user.is_authenticated:
# user logged in and rePOSTed... clean up and let the magic work on its on
if request.session.has_key(referer_key):
del request.session[referer_key]
if request.session.has_key(post_params_key):
del request.session[post_params_key]
elif request.method == 'GET' and request.user.is_authenticated:
print ("dispatch: GET authenticated")
if request.session.has_key(referer_key):
if request.session[referer_key] == request.get_full_path():
newRequest = HttpRequest()
newRequest.COOKIES = request.COOKIES
newRequest.META = request.META
newRequest.FILES = request.FILES
newRequest.path = request.path
newRequest.path_info = request.path_info
newRequest.method = 'POST'
newRequest.resolver_match = request.resolver_match
newRequest.content_type = request.content_type
newRequest.content_params = request.content_params
q = QueryDict(urlencode(request.session[post_params_key]))
newRequest.POST = q
newRequest.session = request.session
newRequest.user = request.user
self.request = newRequest
del request.session[referer_key]
del request.session[post_params_key]
return super().dispatch(newRequest, *args, **kwargs)
# we clean up as it seems the user has moved on.
del request.session[referer_key]
del request.session[post_params_key]
return super().dispatch(request, *args, **kwargs)
成功登录后,它实际上会重新创建 HttpRequest 对象并将其转换为 POST 请求,然后再调用super().dispatch(...)
如果在 a 中使用FormView,请确保使用足够的 POST 数据重新创建表单,如下所示:
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
return super().post(request, *args, **kwargs)
为我工作。享受!