将初始数据从URL模式或发布数据插入到SessionWizardView表单字段中?

时间:2014-11-09 05:20:21

标签: django url design-patterns formwizard

我在这个问题上的资源非常耗尽,所以我必须向社区提交一个问题。

情景:

在我的urls.py文件中,我有一个类似的模式:

url(r'^entry_form/(?P<sheet_id>\d+)/', SheetWizard.as_view([Sheet1,Sheet2,Sheet3])),

当用户访问类似&#34; 127.0.0.1/myapp/entry_form/77"的网址时;我想让Django渲染Sheet1,但其中一个字段的值为&#34; 77&#34;最初进入。

初​​论:

我的forms.py文件类似于:

class Sheet1(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(Sheet1, self).__init__(*args, **kwargs)
        #create a helper object
        self.helper = FormHelper(self)
        #dont render the form tags
        self.helper.form_tag = False
        #Make a nice layout
        self.helper.layout = Layout(
             TabHolder(
                             Tab(
                                 'Sheet Information', #Tab name text
                                     PrependedText('sheet_field', 'Django-'), #The field with prepended text
                             )
             )
        #Now set the initial value of the field to sheet_id from url pattern
        self.fields['sheet_field'].initial = str(sheet_id)+'-'+ str( time() ).replace('.','_')
        #??? Not sure where to get sheet_id from???

注意最后一行有一个名为&#34; sheet_id&#34;的变量,它应该是值&#34; 77&#34;来自用户输入的网址格式。

问题:

到目前为止,我不确定如何访问值&#34; sheet_id&#34;来自我的forms.py或views.py文件中的url模式。由于这是一个基于类的视图,我不能简单地创建关键字&#34; sheet_id = None&#34;,也就是说这样的东西不起作用:

class SheetWizard(SessionWizardView, sheet_id=None):
    #this breaks

我已经能够使用request.GET将一些数据输入到views.py中 和#34; 127.0.0.1/myapp/entry_form/?sheet_id = 77&#34;但我不知道如何将其传递到SessionWizardView用户会话的第一种形式。

如果有人能帮助我,我将不胜感激。 谢谢你所有的善意!

2 个答案:

答案 0 :(得分:1)

使用向导的dispatch方法:

def dispatch(self, request, *args, **kwargs):
    self.sheet_id = kwargs.get('sheet_id', None)
    return super(SheetWizard, self).dispatch(request, *args, **kwargs)

然后在get_form_initial方法中使用self.sheet_id来填充表单的初始值。

答案 1 :(得分:1)

感谢mariodev指出我正确的方向。

我发现这个代码组合适用于我的应用程序:

[urls.py]

url(r'^entry_form/(?P<sheet_id_initial>\d+)/', SheetWizard.as_view([Sheet1,Sheet2,Sheet3])), 

[views.py]

class SheetWizard(SessionWizardView):
    #some code here
    def dispatch(self, request, *args, **kwargs):
        self.sheet_id_initial = kwargs.get('sheet_id_initial', None)
        return super(SheetWizard, self).dispatch(request, *args, **kwargs)

    def get_form_initial(self, step):
        initial = self.initial_dict.get(step, {})
        if int(step) == 0:
            initial.update({ 'sheet_id_initial': self.sheet_id_initial })
        return initial

[forms.py]

class Sheet1(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(Sheet1, self).__init__(*args, **kwargs)
        #create a helper object
        self.helper = FormHelper(self)
        #dont render the form tags
        self.helper.form_tag = False
        #Make a nice layout
        self.helper.layout = Layout(
             TabHolder(
                             Tab(
                                 'Sheet Information', #Tab name text
                                     PrependedText('sheet_field', 'Django-'), #The field with prepended text
                             )
             )
        #finally lets set the initial values
        if 'initial'in kwargs:
            initial = kwargs.pop('initial')
            print initial
            if 'sheet_id_initial' in initial:
                sheet_id_initial = initial.pop('sheet_id_initial')
                #this is where the value from sheet_id_initial is initialized in the field :)
                self.fields['sheet_id_initial'].initial = str(sheet_id_initial)+'-'+ str( time() ).replace('.','_')

然而,这确实会产生一个新问题。我现在可以访问第一个表单,并且url模式中的sheet_id_initial的值已按预期添加到表单字段中,但是当按下提交按钮时,由于POST没有将sheet_id_initial部分添加到请求网址。

[返回页面]

“” “”

找不到页面(404) 请求方法:POST 请求网址:http://192.ip.address.1:8001/sheets/entry_form/

使用first_project.urls中定义的URLconf,Django按以下顺序尝试了这些URL模式:

^admin/
^Users/
^sheets/ ^entry_form/(?P<sheet_id_initial>\d+)/

当前网址sheet / entry_form /与其中任何一个都不匹配。

您看到此错误,因为您的Django设置文件中有DEBUG = True。将其更改为False,Django将显示标准的404页面。

“” “”

[其他信息]

要更改从URL模式或POST数据获取sheet_id变量的方式,请直接进行:

首先将urls.py中的正则表达式模式更改为简单匹配,如:

urlpatterns = patterns('',
    url(r'^entry_form/', SheetWizard.as_view([Sheet1,Sheet2,Sheet3])), 
    #url(r'^entry_form/(?P<sheet_id_initial>\d+)/', SheetWizard.as_view([Sheet1,Sheet2,Sheet3])), #'sheet_id_initial' would be picked up by "self.sheet_id_initial = kwargs.get('sheet_id_initial', None)" in SheetWizard.dispatch()

然后在views.py中更改调度覆盖方法中的赋值,如下所示:

class SheetWizard(SessionWizardView):
    def dispatch(self, request, *args, **kwargs):
        #self.sheet_id = kwargs.get('sheet_id_initial', None) #used to grab sheet_id_initial from url pattern
        if self.request.GET.has_key('sheet_id_initial'):
            self.sheet_id_initial = self.request.GET['sheet_id_initial'] #used to grab sheet_id_initial from QueryDict
        return super(SheetWizard, self).dispatch(request, *args, **kwargs)

最后,如果您正在获取MultiValueDictKeyError,我向get_form_initial()添加了一个try-except块,用于测试是否存在从调度方法声明的变量,如果POST数据存在(但我不确定是否这是处理这个问题的最好方法..)

所以在views.py中将这些行添加到get_form_initial():

class SheetWizard(SessionWizardView):
    def get_form_initial(self, step):
        initial = self.initial_dict.get(step, {})
        if step == "0":
            try:
                self.sheet_id_initial #check for variable existence 
                #if we get past this line then the variable existed and we can update initial data
                initial.update({ 'sheet_id_initial': self.sheet_id_initial })
            except:
                #variable didn't exist so lets just move on..
                pass                 
        return initial

[更新 - 迄今为止的最佳解决方案]

这个会话向导和基于类的视图可能有点棘手。我发现前面这两种方法都有某种方式存在缺陷,并且意识到我已经过度复杂化了一些事情。 但是大多数以前的代码都是必不可少的,但我没有POST或URL模式,而是将POST数据存储在会话中,并在不同URL的表单中访问它!

现在我有一个用户从地址开始的表单: “http://192.ip.address.1:8001/sheets/start/”在表单中有两个字段:“part_id_initial”和“sheet_id_initial”

按下提交后,用户将被重定向到:“http://192.ip.address.1:8001/sheets/entry_form/” 但是HTTP的限制是POST数据不能与重定向一起使用。

所以你可以通过修改上面的代码来保存会话POST数据并以另一种形式使用它:

urls.py

url(r'^start/', 'process_forms.views.GetStarted'),
url(r'^entry_form/', SheetWizard.as_view([Sheet1,Sheet2,Sheet3])), 

views.py

def GetStarted(request):
    form = gettingStarted(request.POST or None)
    if request.method == 'POST':
        if form.is_valid():
            data = form.cleaned_data
            request.session['_old_post'] = request.POST #Store POST to be passed to SheetWizard
            return redirect('/sheets/entry_form/')            
    return render_to_response('get_started.html',
                              locals(),
                              context_instance=RequestContext(request))

class SheetWizard(SessionWizardView):
    def dispatch(self, request, *args, **kwargs):
        old_post = request.session.get('_old_post') #Retrieve old POST data to set initial values on session form 
        if old_post.has_key('sheet_id_initial') and old_post.has_key('part_id_initial'):

            self.sheet_id_initial = old_post['sheet_id_initial'] #used to grab sheet_id from QueryDict
            self.part_id_initial = old_post['part_id_initial'] #used to grab sheet_id from QueryDict
        return super(SheetWizard, self).dispatch(request, *args, **kwargs)

其余几乎与上面完全相同。 将POST数据保存到会话中是最干净的,也是迄今为止我发现的最优雅的解决方案。

希望这有帮助!!