Juan Carlos Asuncion
Juan Carlos Asuncion

Reputation: 967

Django: saving dynamic forms with foreign key

I would like to seek assistance and guidance to my problem.

I have the following models:

class myinfo(models.Model):
    name = models.CharField(max_length=30, null=True)


class mynumbers(models.Model):
    fkey = models.ForeignKey("myinfo")
    Job_Position = models.CharField(max_length=30, null=True)

The mynumbers model is dynamically generated via django-dynamic-formset.

My form

class info(ModelForm):
    name= forms.CharField( max_length=20)

    class Meta:
        model = APPLICANT_DATA
        fields = ('name',)

class numbers(ModelForm):
    number = forms.CharField( max_length=20)

    class Meta:
        model = APPLICANT_DATA
        fields = ('number',)

If you want to save your dynamic form fields you have to do this in views

for field in formset:
    field.save()

My views:

def index(request):

    aformset = formset_factory(numbers)
    formset = aformset(request.POST)
    form = info(request.POST)

    if request.method == 'POST':

        if form.is_valid():
            if formset.is_valid():
                for field in formset:
                    formset.save()

                form.save()

But the problem starts when my dynamically generated field has a foreign key(mynumbers) which raises an error must be a myinfo instance. How would I save the 2 forms where mynumbers has a foriegn key to myinfo? Is there a better way to what I did? Thank you in advance,

Upvotes: 1

Views: 935

Answers (1)

Ian Price
Ian Price

Reputation: 7616

This is where inlineformset_factory would be used. This allows you to have a parent model and a number of child models (related w/ parent via a foreignkey) and save them together. There are many arguments that can be passed to the inlineformset_factory in order to customize behavior (such as the minimum and maximum number of inline forms allowed, whether the user can delete inline forms, etc.) but the crux is shown below.

# views.py

from django.forms.models import inlineformset_factory
from my_app.forms import numbers as NumberForm
from my_app.forms import info as InfoForm
from my_app import models

myFormset = inlineformset_factory(models.myinfo,
    models.mynumbers,
    form=NumberForm
)

def index(request):
    if request.POST:
        form = InfoForm(request.POST)
        if form.is_valid():
            info = form.save(commit=False)
            formset = myFormset(request.POST, instance=info)
            if formset.is_valid():
                info.save()
                formset.save()
                return HttpResponse('saved successfully')
    else:
        form = InfoForm()
        formset = myFormset(instance=models.myinfo())
    return render_to_response("recipes/submit.html", {
                                                    "form": form,
                                                    "formset":formset,    
                                                    }, 
                            context_instance=RequestContext(request))

Please note: In your question, you typed for field in formset: formset.save(). A formset is a collection of forms, not a collection of fields.

Formsets can be tricky and require the template rendered correctly with additional template components that are not part of regular forms (such as the management_form variable that allows for Django to properly process what has been added/deleted/moved/changed). It's definitely worth doing some tutorials in order to get an idea of best practices so that you don't go down a troubleshooting rabbithole w/ your custom implementation. I suggest this post from Charles Leifer as a good entry to get acquainted with the basics.

Upvotes: 1

Related Questions