我已经编写了一个我希望成为可重复使用的Django应用程序,但我在如何使表单后处理变得灵活方面遇到了一些难题。我的视图代码的简化版本看起来像:
def do_form(request, entity_id, template_name, success_url):
form = MyForm(request.POST or None)
if request.method =='POST':
if form.is_valid():
#do some business logic
return HttpResponseRedirect(finished_url)
return render_to_response(template_name,
{'form': form},
context_instance=RequestContext(request))
我遵循了James Bennets在《实用Django项目》一书中的建议,因此您现在可以在url conf中配置模板和成功url,因此例如,我的url conf可能如下所示:
urlpatterns = patterns('myapp.views',
url(r'^do/(?P<entity_id>d+)/$',
view = 'do_form',
name = 'do_form_view',
kwargs={'template_name':'form.html',
'success_url':'/finish/'},),
url(r'^finish/$',
view = 'finish',
name = 'finish_view')
)
这一切都很好,但当我在现实世界的应用程序中使用它时,我发现自己处于这样一种情况,即该表单位于某些工作流的中间,我希望成功url类似于/continue/<workflow_id>/
,而问题是在url-conf中只能有一个硬编码的url,并且每次我调用do_form代码时,workflow_id都会有所不同。
有人能提出绕过这个问题的方法吗?
您可以通过更改以下内容来实现。。
在视图中的do_form()
中。py将return HttpResponseRedirect
更改为
return HttpResponseRedirect('/continue/%s' %(workflowid))
在urls.py中,您可以使用
url(r'^continue/(?P<workflowid>d+)/$',
view = 'continue',
name = 'continue_view')
对于视图中的continue()
视图。py
def continue(request, workflowid=None):
...
这样。。无论何时访问不带数字的url /continue/
,workflowid都将等于None
。每隔一段时间,如果您确实为/continue/23/
等附加了工作流id,那么在continue()
视图中,您可以通过变量workflowid
访问该id。
当您将假设的"flexible"success_url传递给视图时,该视图必须提供所需的标识符。因此,如果URL和视图不匹配,我们无法避免两者之间的"违约"。
因此,如果我们要有灵活的URL,就必须执行某种合同,如果我们通过URL的特殊语法这样做,就不会失去通用性
'finished_url': '/finish/<workflow_id>/'
然后,当然,视图必须通过字符串替换来实例化变量,以遵守合同的规定:而不是
return HttpResponseRedirect(finished_url)
你会有
return HttpResponseRedirect(finished_url.replace('<workflow_id>', WorkflowID))
这应该使事情保持合理的简单。
在重用代码时,您必须记住<workflow_id>
是应用程序用来调用工作流id的任何东西,这就是为什么我使用复杂的字符串,如workflow_id
,而不是id
或$1
。
EDIT:我本来打算添加下一步的代码(在finish参数中拦截工作流ID),但我发现keithxm23击败了我:-)
你可以用人们多年来"覆盖"Django基于函数的通用视图的方法来做到这一点:只需将视图包装在另一个视图中:
def custom_do_form(request, entity_id, template_name, success_url):
template_name = some_method_to_get_template()
return do_form(request, entity_id, template_name, success_url)