Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#29160 closed Bug (invalid)

Django ModelForm doesn't parse foreign keys in initial= kwarg.

Reported by: Hameer Abbasi Owned by: nobody
Component: Forms Version: 1.11
Severity: Normal Keywords: initial
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Hameer Abbasi)

Django forms don't parse foreign keys in the initial= kwarg. It gives a "NOT NULL constraint failed" even if the said data has been specified. This is inconvenient for forms since an instance can be specified but critical for formsets where it can't.

Relevant files:

models.py

Code highlighting:

from django.db import models


class BaseModel(models.Model):
    pass


# Create your models here.
class SimpleModel(models.Model):
    field = models.IntegerField(default=0)
    hidden_fk = models.ForeignKey(BaseModel, null=False)

forms.py

Code highlighting:

from django import forms

from . import models


class SimpleForm(forms.ModelForm):
    class Meta:
        model = models.SimpleModel
        fields = ['field']


SimpleFormset = forms.modelformset_factory(models.SimpleModel, fields=['field'], extra=3)  

views.py

Code highlighting:

from django import views
from django.template import loader
from django.http import HttpResponse

from . import forms
from . import models


# Create your views here.
class FormView(views.View):
    template = 'thing/form.html'

    def get(self, request):
        context = {'form': forms.SimpleForm()}
        template = loader.get_template(self.template)

        return HttpResponse(template.render(context, request))

    def post(self, request):
        base_model = models.BaseModel.objects.get(id=1)
        form = forms.SimpleForm(request.POST, initial={'hidden_fk': base_model})
        context = {'form': form}
        template = loader.get_template(self.template)

        simple_model = form.save(commit=False)
        simple_model.field = 1
        form.save()

        return HttpResponse(template.render(context, request))


class FormSetView(views.View):
    template = 'thing/formset.html'

    def get(self, request):
        context = {'formset': forms.SimpleFormset()}
        template = loader.get_template(self.template)

        return HttpResponse(template.render(context, request))

    def post(self, request):
        base_model = models.BaseModel.objects.get(id=1)

        formset = forms.SimpleFormset(
            request.POST,
            initial=[{'hidden_fk': base_model}] * forms.SimpleFormset.extra
        )

        context = {'formset': formset}
        template = loader.get_template(self.template)

        if formset.is_valid():
            formset.save()

        return HttpResponse(template.render(context, request))

Attachments (1)

sample_project.zip (26.3 KB ) - added by Hameer Abbasi 6 years ago.
Sample project demonstrating the issue.

Download all attachments as: .zip

Change History (5)

by Hameer Abbasi, 6 years ago

Attachment: sample_project.zip added

Sample project demonstrating the issue.

comment:1 by Hameer Abbasi, 6 years ago

Type: UncategorizedBug

comment:2 by Hameer Abbasi, 6 years ago

Description: modified (diff)

comment:3 by Tim Graham, 6 years ago

Resolution: invalid
Status: newclosed

This looks like a misunderstanding of how Form.initial works. From the documentation:

[Form.initial] values are only displayed for unbound forms, and they’re not used as fallback values if a particular value isn’t provided.

I only looked at this briefly, so if I've misunderstood the issue please reopen and point to the incorrect code in Django.

comment:4 by Hameer Abbasi, 6 years ago

I won't reopen since you're probably right, but then there is no way to pass an instances= to a ModelFormSet. Because of this, when certain FKs are missing, you can't validate them later because the ModelFormSet fails to validate even with commit=False. This is probably a separate issue though. See https://stackoverflow.com/questions/48961675/modify-data-in-formset-before-validation for details on what I want to do, except I want to inject an FK.

Note: See TracTickets for help on using tickets.
Back to Top