saving to two models from one class view

83 views
Skip to first unread message

Brad Rice

unread,
Jan 9, 2014, 4:43:42 PM1/9/14
to django...@googlegroups.com
I have been banging around trying to write to two models from one view for a couple days and just cannot figure it out.

I am using a CreateView. I want to write to a model with just the created_by user and a default value of False in app_complete to. I'm getting this error:

[u'ManagementForm data is missing or has been tampered with']

Could anyone help me figure out how to save to two models from a class view?

Models I'm trying to save to:

class Application(models.Model):
    app_complete = models.BooleanField(default=False)
    created_by = models.ForeignKey(User, unique=True)


class Applicant(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    title = models.CharField(max_length=100)
... more fields

My forms view:

class RegistrantForm(forms.ModelForm):
    ADDRESS_CHOICES = (('home', 'Home',), ('business', 'Business',))
    address_type = forms.ChoiceField(
        choices=ADDRESS_CHOICES, widget=forms.Select
    )
    street2 = forms.CharField(required=False)
    cell_phone = forms.CharField(required=False)
    fax_phone = forms.CharField(required=False)

    class Meta:
        model = Applicant
        fields = ('first_name', 'last_name', 'title', 'years_at_job', 'street1', 'street2', 'city', 'state', 'zip', 'address_type', 'residence', 'phone', 'cell_phone',
                  'fax_phone')
        exclude = ['created_by']   # Will be taken from the request

class ApplicationForm(forms.ModelForm):
    app_complete = forms.BooleanField(required=True, label="Check this to confirm the application is complete.")

    class Meta:
        model = Application
        fields = ('app_complete', 'created_by')


ApplicationFormSet = inlineformset_factory(Application, Applicant)

Then my view which doesn't work:

class RegistrantCreate(CreateView):
    model = Applicant
    form_class = RegistrantForm
    template_name = 'applicant_form.html'
    success_url = '/requestform/update2/'

@method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(RegistrantCreate, self).dispatch(*args, **kwargs)

    def get(self, request, *args, **kwargs):
        """
        Handles GET requests and instantiates blank versions of the form
        and its inline formsets.
        """
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        application_form = ApplicationFormSet()
        return self.render_to_response(
            self.get_context_data(form=form,
                                  applicaton_form=application_form))

    def post(self, request, *args, **kwargs):
        """
        Handles POST requests, instantiating a form instance and its inline
        formsets with the passed POST variables and then checking them for
        validity.
        """
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        application_form = ApplicationFormSet(self.request.POST)
        if (form.is_valid() and application_form.is_valid() and
            application_form.is_valid()):
            return self.form_valid(form, application_form)
        else:
            return self.form_invalid(form, application_form)

    def form_valid(self, form, application_form):
        """
        Called if all forms are valid. Creates a Recipe instance along with
        associated Ingredients and Instructions and then redirects to a
        success page.
        """
        self.object = form.save(commit=False)
        self.object.created_by = self.request.user
        self.object = form.save()
        application_form.instance = self.object
        application_form.save(commit=False)
        application_form.instance.created_by = self.request.user
        application_form.save()
        return HttpResponseRedirect(self.get_success_url())

    def form_invalid(self, form, application_form):
        """
        Called if a form is invalid. Re-renders the context data with the
        data-filled forms and errors.
        """
        return self.render_to_response(
            self.get_context_data(form=form,
                                  application_form=application_form)
        )

trojactory

unread,
Jan 10, 2014, 2:49:43 AM1/10/14
to django...@googlegroups.com
Hi Brad,

At the moment, two models do not have any relationship. I think you made an error in Line 3:

    created_by = models.ForeignKey(User, unique=True)

I think you meant "Applicant" instead of User.

Regards,
Arun

Brad Rice

unread,
Jan 10, 2014, 8:37:25 AM1/10/14
to django...@googlegroups.com
Thanks for the help.

I've modified the Applicant model:

class Application(models.Model):
    app_complete = models.BooleanField(default=False)
    applicant = models.ForeignKey('Applicant', unique=True)
    created_by = models.ForeignKey(User, related_name='+')

There is really no data being entered by the end user, I just want to create a row with the application_id (auto generated), user, a relation to the applicant table and the default value of false in the app_complete field. When I fill out the form and post I still get Validation Errors on the related formset.

[u'ManagementForm data is missing or has been tampered with']

My template is simple:

{% extends "base.html" %}
{% block title %}Add Applicant Information{% endblock %}
{% block head %}Add Applicant Information{% endblock %}
{% block content %}
<form action="." method="post">
            {% csrf_token %}
            <div>
                {{ form.as_p }}
            </div>
                {{ application_form.management_form }}
                {{ application_form.non_form_errors }}
<input type="submit" value="Add" />
</form>
{% endblock %}

I'm really feeling the newbie moniker.

Dan Gentry

unread,
Jan 14, 2014, 4:59:13 PM1/14/14
to django...@googlegroups.com
With a formset, like your application form, the template could look like one of these examples:

<form method="post" action="">
    {{ formset.management_form }}
    <table>
        {% for form in formset %}
        {{ form }}
        {% endfor %}
    </table>
</form>
<form method="post" action="">
    <table>
        {{ formset }}
    </table>
</form>

I'm not sure if this will do everything you want, but will get you past the current error.
Reply all
Reply to author
Forward
0 new messages