如何使我的邮寄表格处理更加灵活



我已经编写了一个我希望成为可重复使用的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()中。pyreturn 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)

最新更新