user9092892
user9092892

Reputation:

Trying to save two forms, column cannot be null

I have three models bound together by foreign keys: Course > Lecture > FileUpload. I tried to create a form for Lecture model, but I actually ended up creating two forms, another one for FileUpload. And every time I try to submit the forms, I get error:

Exception Type: IntegrityError at /courses/teacher/classroom/
Exception Value: (1048, "Column 'lecture_id' cannot be null")

The Lecture form actually submits the information, and I think that the error is related to the second form. Thing is that I want the user to be able to upload many files for the same lecture, just like in the database, and currently only one file could be uploaded which is not working.

View:

def classroom(request):
    if request.method == 'POST':
        form1 = LectureForm(request.POST)
        form2 = FileForm(request.POST, request.FILES)
        if form1.is_valid() and form2.is_valid():
            form1.save()
            form2.save()
            return redirect('courses/courses.html')
    else:
        form1 = LectureForm()
        form2 = FileForm()
    context = {'teacher_data': TeacherData.objects.all(),
               'teachers': Teacher.objects.all(),
               'courses': Course.objects.all(),
               'form1': form1,
               'form2': form2,
               }
    return render(request, 'courses/classroom.html', context)

Forms:

class LectureForm(forms.ModelForm):
    class Meta:
        model = Lecture
        fields = ('course', 'lecture_title', 'lecture_category', 'content')


class FileForm(forms.ModelForm):
    class Meta:
        model = FileUpload
        fields = ('files',)

Models:

class Course(models.Model):
    name = models.CharField(max_length=50, unique=True)


class Lecture(models.Model):
    LECTURE_CHOICES = (
        ('Courses', 'Courses'),
        ('Seminars', 'Seminars'),
    )
    course = models.ForeignKey('Course', on_delete=models.CASCADE, default='', related_name='lectures',)
    lecture_category = models.CharField(max_length=10, choices=LECTURE_CHOICES, default='Courses',)
    lecture_title = models.CharField(max_length=100, blank=True, null=True)
    content = models.TextField(blank=True, null=True)


class FileUpload(models.Model):
    files = models.FileField(upload_to='documents', null=True, blank=True)
    lecture = models.ForeignKey('Lecture', related_name='files', on_delete=None, default=None)

Traceback: https://pastebin.com/5ViFarGP

Upvotes: 0

Views: 618

Answers (1)

neverwalkaloner
neverwalkaloner

Reputation: 47364

To fix the error you need to pass lecture object to file before saving it to DB:

if form1.is_valid() and form2.is_valid():
    lecture = form1.save()
    file = form2.save(commit=False)
    file.lecture = lecture
    file.save() 

To create multiple related object at the same time you can use formsets. In your case you need to do something like this:

from django.forms.models import inlineformset_factory
FileFormset = inlineformset_factory(Lecture, FileUpload, fields=('files',))

if request.method == 'POST':
    form1 = LectureForm(request.POST)
    if form1.is_valid():
        lecture = form1.save()
        formset = FileFormset(request.POST, request.FILES, instance=lecture)
        if formset.is_valid():
            formset.save()

    return redirect('courses/courses.html')
else:
    form1 = LectureForm()
    formset = FileFormset()
context = {'teacher_data': TeacherData.objects.all(),
           'teachers': Teacher.objects.all(),
           'courses': Course.objects.all(),
           'form1': form1,
           'formset': formset,
           }

In template add inside <form> tag:

{{ formset.management_form }}
{% for form in formset %}
    {{ form }}
{% endfor %}

Upvotes: 1

Related Questions