我们有以下设置。
CreateView
,这就是我现在称之为的形式)。redirect_to
并且已创建记录的DetailView
。CreateView
生成的HTML从浏览器缓存中获取,并使用他们输入的数据重新填充。起初我认为Django使用的Post-Redirect-Get(PRG)模式应该可以防止这种情况发生。在调查之后,似乎PRG只是为了防止可怕的“你想重新提交表格吗?”#34;对话。死路。
点击后退按钮后,所有内容都从缓存中获取,因此我们无法从Django代码与用户交互。为了尝试阻止本地缓存,我们使用CreateView
修饰了@never_cache
。这对我们没有任何作用,页面仍然是从缓存中检索的。
我们正在考虑对window.referrer进行onLoad
检查的脏JavaScript技巧,如果引用者看起来像前面提到的DetailView
,则手动清理表单和/或通知用户。当然这感觉完全错了。然后,我们的数据库中的半重复记录也是如此。
然而,似乎不太可能我们第一个被这个困扰,我想在这里询问StackOverflow。
理想情况下,我们会告诉浏览器缓存表单是一个很大的NO,浏览器会监听。我们再次使用@never_cache
,但显然这还不够。适用于Chrome,Safari和Firefox。
期待任何见解!谢谢!
答案 0 :(得分:1)
如果POST请求来自同一页面以外的推荐人,可能不会处理该请求吗?
from urllib import parse
class CreateView(...):
def post(self, *args, **kwargs):
referer = 'HTTP_REFERER' in self.request.META and parse.urlparse(self.request.META['HTTP_REFERER'])
if referer and (referer.netloc != self.request.META.get('HTTP_HOST') or referer.path != self.request.META.get('PATH_INFO')):
return self.get(*args, **kwargs)
...
答案 1 :(得分:0)
我知道我参加这个聚会很晚,但这可能会帮助其他人寻找答案。
在解决同一问题时发现了这个问题,这是我使用人为因素而不是技术因素的解决方案。如果从CreateView提交后,用户最终将使用新创建的对象的UpdateView(除了标题和底部的按钮外看起来完全一样),将不使用后退按钮。
一种技术解决方案可能是创建一个模型字段来保存UUID,并创建一个传递给创建表单的UUID作为隐藏字段。当按下Submit时,form_valid
可以在数据库中检入具有该UUID的对象,并拒绝创建重复的对象(unique=True
将在数据库级别强制执行该操作)。
这里是示例代码(略作删除以删除雇主可能不希望在公共场所看到的东西)。它使用django-crispy-forms使事情变得轻松漂亮。通过从客户表上的按钮进入创建视图,该视图传递客户帐号,而不是其记录的Django ID。
网址
url(r'enter/(?P<customer>[-\w]+)/$', JobEntryView.as_view(), name='job_entry'),
url(r'update1/(?P<pk>\d+)/$', JobEntryUpdateView.as_view(), name='entry_update'),
观看次数
class JobEntryView( LoginRequiredMixin, CreateView):
model=Job
form_class=JobEntryForm
template_name='utils/generic_crispy_form.html' # basically just {% crispy form %}
def get_form( self, form_class=None):
self.customer = get_object_or_404(
Customer, account = self.kwargs.get('customer','?') )
self.crispy_title = f"Create job for {self.customer.account} ({self.customer.fullname})"
return super().get_form( form_class)
def form_valid( self, form): # insert created_by'class
#form.instance.entered_by = self.request.user
form.instance.customer = self.customer
return super().form_valid(form)
def get_success_url( self):
return reverse( 'jobs:entry_update', kwargs={'pk':self.object.pk, } )
# redirect to this after entry ... user hopefully won't use back because it's here already
class JobEntryUpdateView( LoginRequiredMixin, CrispyCMVPlugin, UpdateView):
model=Job
form_class=JobEntryForm
template_name='utils/generic_crispy_form.html'
def get_form( self, form_class=None):
self.customer = self.object.customer
self.crispy_title = f"Update job {self.object.jobno} for {self.object.customer.account} ({self.object.customer.fullname})"
form = super().get_form( form_class)
form.helper[-1] = ButtonHolder( Submit('update', 'Update', ), Submit('done', 'Done', ), )
return form
def get_success_url( self):
print( self.request.POST )
if self.request.POST.get('done',None):
return reverse('jobs:ok')
return reverse( 'jobs:entry_update',
kwargs={'pk':self.object.pk, } ) # loop until user clicks Done