在Django中的一个模板中显示两个表单

时间:2014-08-20 10:07:23

标签: python django

我的目标是在一个模板中使用两个模型。我已经尝试了各种各样的方法并且没有成功。最初我有2个视图,2个模型和两个表单。搜索后,我发现人们使用inlineformsets。所以我删除了其中一个视图并设置了inlineformset。 这是我目前所处的地方,似乎正在撞墙。

模板呈现给浏览器和' object_list' part根据需要显示数据库内容,并且'形式' part渲染表单并正确验证/保存数据。问题在于' formset'。没有字段被渲染(我希望看到一个下拉列表,因为该字段是一个外键)并且当提交'我按下了按钮:

AttributeError at /settings/

'NoneType' object has no attribute 'save'

非常感谢任何寻找错误的帮助或关于替代解决方案的指示。

守则:

models.py

from django.db import models

class RevisionSettings(models.Model):    
    global_revision_type = models.CharField(max_length = 5, unique=True, blank = True)
    global_revision_description = models.CharField(max_length = 300, unique=True, blank = True)

    class Meta:
        ordering = ["global_revision_type"]

    def __unicode__(self):  
        return u'%s %s' % (self.global_revision_type, self.global_revision_description)


class RevisionDefaultType(models.Model):
    defaultrevisiontype = models.ForeignKey(RevisionSettings)

    class Meta:
        ordering = ["defaultrevisiontype"]

    def __unicode__(self):  
        return unicode(self.defaultrevisiontype)

views.py

class RevisionSettingsView(CreateView):
    template_name = 'settings/revisionsettings_view.html'
    model = RevisionSettings
    form_class = SettingsForm
    success_url = reverse_lazy('globalsettings')
    success_message = 'Successfully added your new revision type'

    def get(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        formset = SettingsFormSet(instance = RevisionSettings)
    return self.render_to_response(
        self.get_context_data(form=form,
                              formset=formset))

    def post(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        formset = SettingsFormSet(self.request.POST)
        if 'rev_settings_form_1' in self.request.POST:
            if form.is_valid():
                return self.form_valid(form)
            else:
                return self.form_invalid(form)
        elif 'rev_settings_form_2' in self.request.POST:
            if formset.is_valid():
                return self.formset_valid(formset)
            else:
                return self.form_invalid(formset)

    def form_valid(self, form):
        self.object = form.save()
        self.object.save()
        return HttpResponseRedirect(self.get_success_url())

    def formset_valid(self, formset):
        self.object.save()
        formset.instance = self.object
        formset.save()
        return HttpResponseRedirect(self.get_success_url())

    def form_invalid(self, form, formset):
        return self.render_to_response(self.get_context_data(form=form,formset=formset))

    def get_context_data(self, **kwargs):
        kwargs['object_list'] = RevisionSettings.objects.order_by('global_revision_type')
        return super(RevisionSettingsView, self).get_context_data(**kwargs)

forms.py

from django import forms
from django.forms.models import inlineformset_factory

from .models import RevisionSettings, RevisionDefaultType

class SettingsForm(forms.ModelForm):

    class Meta:
        model = RevisionSettings

class DefaultSettingsForm(forms.ModelForm):

    class Meta:
        model = RevisionDefaultType

SettingsFormSet = inlineformset_factory(RevisionSettings, RevisionDefaultType)

revisionsettings_view.html

(我删除了大部分HTML样式以保持信息的正确性)

{% extends 'base_private.html' %}

{% block content %}

    {% for object in object_list %}

        <tr>
            <td align="center">{{ object.global_revision_type }}</td>
            <td align="center">{{ object.global_revision_description }}</td>
            <td align="center"><a href="/settings/{{ object.id }}/delete" class="tooltip-test" title="" data-original-title="Delete selected revision type"><span class="glyphicon glyphicon-remove-circle"></span></a></td>
        </tr>

    {% endfor %}

    <form action = '{{ action }}' method = 'POST' class="form-horizontal" role="form">
        {% csrf_token %}

        <tr>
            <td align="center">
                {{ formset.management_form }}
                {% for form in formset %}
                    {{ form.id }}
                    {{ form.defaultrevisiontype.label_tag }}
                    {{ form.defaultrevisiontype }}
                {% endfor %}
            </td>
        </tr>

        <span class="input-group-addon">
                <input type = 'submit' name = 'rev_settings_form_2' value = 'Update Default Revision Type' class = 'btn btn-success'>
        </span>

            <td align="center">{{ form.global_revision_type }}{{ form.global_revision_type.errors }}</td>
            <td align="center">{{ form.global_revision_description }}{{ form.global_revision_description.errors }}</td>
        </tr>

        <span class="input-group-addon">
                <input type = 'submit' name = 'rev_settings_form_1' value = 'Add Revision Type' class = 'btn btn-success'>
        </span>

    </form>

{% endblock %}

2 个答案:

答案 0 :(得分:1)

Formsets对于两种形式来说都是过度杀伤力。这实际上并不太难,但记录不完整。您可以将两个表单设置为相同的表单类型,只需给出一个前缀。

def parent_apply(request):
  if request.method == 'POST':
    parent_form = SignupForm(request.POST, prefix="parent")
    student_form = StudentApplyForm(request.POST, prefix="student")
    if parent_form.is_valid() and student_form.is_valid():
      parent = parent_form.save()
      student = student_form.save(parent)
    else: messages.error(request, "Please correct the errors marked in red.")
  else:
    parent_form = SignupForm(prefix="parent")
    student_form = StudentApplyForm(prefix="student")

  return render_to_response('template_path/forms.html', { 'parent_form':parent_form, 'student_form':student_form }, context_instance=RequestContext(request))

表单只是常规的Django表单,不需要特殊设置。您可以更改他们验证的顺序并保存一个,即使另一个没有验证您是否选择。

在HTML模板中,将两个表单包装在同一个标​​记中,它们将同时提交。如果希望表单转到不同的视图函数,请指定两个不同的元素。

答案 1 :(得分:0)

感谢所有帮助。指针真的帮助我找到了这个解决方案。主要的变化是'def get&#39;如下所示。我删除了formset并以这种方式传递了表单。

def get(self, request, *args, **kwargs):
     form = self.settings_form_class
     formset = self.default_form_class

     return self.render_to_response(self.get_context_data(form = form, formset = formset))

我不知道这是可能的!再次感谢。