我知道我可以使用诸如@login_required
和@permission_required()
之类的修饰符,或者将视图包含在诸如login_required()
之类的函数中,以重定向用户以提供更多信息(登录这种情况)。成功后,用户将重定向到他最初尝试访问的URL(自动使用URL中的逻辑?next=/
)。
现在,我想将?next=/
逻辑应用于另一种情况。我的用户已登录,并想在该网站上要求保护。要成功做到这一点,他必须提供他的地址。在视图中,我检查所有地址字段是否都不为空。如果这些字段之一为空,则将用户重定向到默认的UpdateView
(窗体)。如果用户填写了这些字段(单击“提交”按钮),我想将他重定向到他来自的URL(尝试声明该片断)。由于这种重定向,检查所有地址字段是否不为空的过程将重新开始,并且如果这次成功,则声明该部分。
在这种情况下?next=/
逻辑如何适用?
views.py
from django.views.generic import RedirectView
from django.http import QueryDict
class ClaimRedirectView(RedirectView):
REQUIRED_FIELDS = ['first_name', 'last_name', 'street', 'street_number', 'zip_code', 'state_province', 'location', 'country']
permanent = False
def get_redirect_url(self, *args, **kwargs):
claimant = get_object_or_404(Creator, user=self.request.user)
missing_fields = [fields.name for fields in claimant._meta.get_fields(include_hidden=False) if fields.name in self.REQUIRED_FIELDS and not getattr(claimant, fields.attname, None)]
if not missing_fields:
return reverse('my-claimed')
messages.info(self.request, 'Please fill in your complete address to proceed')
next = self.request.get_full_path()
path = reverse('creator-update', kwargs={'slug': claimant.slug})
#q = QueryDict('next=%s' % next)
q = 'next=' + next
return '%s?%s' % (path, q)
class CreatorUpdate(LoginRequiredMixin, UpdateView):
model = Creator
slug_field = 'slug'
fields = ['first_name', 'last_name', 'street', 'street_number', 'zip_code', 'location', 'state_province', 'country']
# these two methods only give access to the users own profile but not the others
def user_passes_test(self, request):
if request.user.is_authenticated:
self.object = self.get_object()
return self.object.user == request.user
return False
def dispatch(self, request, *args, **kwargs):
if not self.user_passes_test(request):
return redirect_to_login(request.get_full_path())
return super(CreatorUpdate, self).dispatch(request, *args, **kwargs)
urls.py
path('claim/<uuid:pk>', login_required(views.ClaimRedirectView.as_view()), name='claim')
path('creator/<slug:slug>/update/', views.CreatorUpdate.as_view(), name='creator-update')
creator_form.html
{% extends "base_generic.html" %}
{% block content %}
{% if messages %}
{% for message in messages %}
<p{% if message.tags %} class="{{ message.tags }}"{% endif %}><strong>{{ message }}</strong></p>
{% endfor %}
{% endif %}
<form action="" method="post">
{% csrf_token %}
{{ form.as_ul }}
<input type="submit" value="Submit">
</form>
{% endblock %}
按照@的建议实施上述ClaimRedirectView
时,我进入表单以填写更多信息,并查看正确的url(具有下一个逻辑)。但是当填写表格时,我不会直接进入网址的下一部分。可能与表单(通用UpdateView
)本身有关吗?
答案 0 :(得分:1)
由于视图重定向请求,因此更好的选择是使用RedirectView,并且next
未添加到url配置中,因此会出现错误。
它应该是一个查询字符串,并且CreatorUpdate.get_absolute_url
应该能够从GET
字典中检索参数。即request.GET.get('next')
from django.http import QueryDict
class ClaimRedirectView(RedirectView):
REQUIRED_FIELDS = ['first_name', 'last_name', ...]
permanent = False
def get_redirect_url(self, *args, **kwargs):
claimant = get_object_or_404(Creator, user=self.request.user)
missing_fields = [
f.name for fields in claimant._meta.get_fields(include_hidden=False)
if f.name in REQUIRED_FIELDS and not getattr(claimant, f.attname, None)
]
if not missing_fields:
return reverse('my-claimed')
messages.info(request, 'Please fill in your complete address to proceed')
next = request.get_full_path()
path = reverse('creator-update', kwargs={'slug': claimant.slug}))
q = QueryDict('next=%s' % next)
return '%s?%s' % (path, q.urlencode())
配置为<next:next>
的urls.py并非虚构,即不是命名组。
path('creator/<slug:slug>/update/', views.CreatorUpdate.as_view(), name='creator-update')
path('claim/<uuid:pk>', login_required(views.claim), name='claim')
要将下一个用作CreatorUpdate视图上的重定向路径。
class CreatorUpdate(LoginRequiredMixin, UpdateView):
model = Creator
slug_field = 'slug' # <-- This is already the default
fields = ['first_name', 'last_name', 'street', 'street_number', 'zip_code', 'location', 'state_province', 'country']
# This should be done using the `get_queryset`
def get_queryset(self):
qs = super().get_queryset()
# if request.user.is_authenticated: # Using the LoginRequiredMixin mixin users will already be authenticated.
return qs.filter(user=self.request.user)
def form_valid(self, form):
next = self.request.GET.get('next')
if next:
return redirect(next)
return super().form_valid(form)
答案 1 :(得分:0)
就像在本机login_required
中一样,您将路径保存到next
GET参数:
def claim(request, pk):
claimant = Creator.objects.get(user=request.user)
if claimant.first_name != None and claimant.last_name != None and claimant.street != None and claimant.street_number != None and claimant.zip_code != None and claimant.location != None and claimant.state_province != None::
(...)
else:
next = request.get_full_path()
return HttpResponseRedirect(reverse('creator-update', kwargs={'slug': claimant.slug, 'next': next}))
,然后在creator-update
视图中检查是否存在下一个,并在成功更新后重定向到下一个。您可以将URL存储在隐藏的输入字段中。
我建议就此检查Django内部,特别是django.contrib.auth.user_passes_test
,django.contrib.auth.views.redirect_to_login
和django.contrib.auth.views.LoginView
。根本没有魔术,那里的一切都很简单。对于LoginView
,您应该熟悉基于类的视图。
答案 2 :(得分:0)
将我的原始代码的部分内容和@jackotonye的建议放在一起,可以使用以下代码:
views.py
from django.contrib import messages
from django.views.generic import RedirectView
class ClaimRedirectView(RedirectView):
REQUIRED_FIELDS = ['first_name', 'last_name', 'street', 'street_number', 'zip_code', 'state_province', 'location', 'country']
permanent = False
def get_redirect_url(self, pk, *args, **kwargs):
claimant = get_object_or_404(Creator, user=self.request.user)
missing_fields = [fields.name for fields in claimant._meta.get_fields(include_hidden=False) if fields.name in self.REQUIRED_FIELDS and not getattr(claimant, fields.attname, None)]
if not missing_fields:
piece_instance = PieceInstance.objects.get(pk=pk)
piece_instance.claimant = self.request.user
piece_instance.date_claimed = datetime.date.today()
piece_instance.status = 'c'
piece_instance.save()
return reverse('my-claimed')
messages.info(self.request, 'Please fill in your complete address to proceed')
next = self.request.get_full_path()
path = reverse('creator-update', kwargs={'slug': claimant.slug})
q = 'next=' + next
return '%s?%s' % (path, q)
class CreatorUpdate(LoginRequiredMixin, UpdateView):
model = Creator
slug_field = 'slug'
fields = ['first_name', 'last_name', 'street', 'street_number', 'zip_code', 'location', 'state_province', 'country']
# these two methods only give access to the users own profile but not the others
def user_passes_test(self, request):
if request.user.is_authenticated:
self.object = self.get_object()
return self.object.user == request.user
return False
def dispatch(self, request, *args, **kwargs):
if not self.user_passes_test(request):
return redirect_to_login(request.get_full_path())
return super(CreatorUpdate, self).dispatch(request, *args, **kwargs)
def get_success_url(self):
if 'next' in str(self.request.META.get('HTTP_REFERER')):
return self.request.GET.get('next', '/')
return reverse_lazy('creator-detail', kwargs={'slug': self.object.slug})
urls.py
path('claim/<uuid:pk>', login_required(views.ClaimRedirectView.as_view()), name='claim')
path('creator/<slug:slug>/update/', views.CreatorUpdate.as_view(), name='creator-update')
成功解决我遇到的问题的两个关键步骤是,在ClaimRedirectView
的{{1}}中实际填写并保存参数,并在{{1}中定义if not missing_fields:
方法}。 get_success_url
手动检查字符串CreatorUpdate
是否在URL中,并相应地重定向。