How to save Django Form and Formset at the same time

I have page in which I use a form and formset at the same time. The form is for the thesis information and the formset if for the author.

This the code in my models.py `

class thesisDB(Model):
    thesis_id = models.AutoField(primary_key=True, blank=True, null=False)
    title = models.CharField(max_length=200, blank=True, null=True, unique=True)
    published_date = models.DateField(blank=True, null=True)
    pdf = models.FileField(upload_to='pdf/', blank=True, null=True ,validators=[FileExtensionValidator(['pdf'])],)
    course = models.ForeignKey(ColCourse, default=None, on_delete=models.CASCADE, verbose_name='Course')
    tags = TaggableManager()
    date_created = models.DateField(auto_now_add=True, blank=True, null=True )
    uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=None)
    published_status = models.CharField(max_length=10, choices= THESIS_DECISION, default='Pending')
    abstract = models.TextField(blank=True, null=True)
    hit_count_generic = GenericRelation(HitCount, object_id_field='object_pk', related_query_name='hit_count_generic_relation')
    reason = models.TextField(blank=True, null=True)
    slug = models.SlugField(max_length = 250, null = True, blank = True) 

    def save(self, *args, **kwargs):
        self.title = self.title.title()
        #self.author = self.author.title()
        self.slug = slugify(self.title + "-" + self.author + "-" + str(self.published_date))
        super().save(*args, **kwargs)

    class Meta:
        db_table = 'thesis_storage'
initial_validator = RegexValidator('[A-Z]+.', 'Initial must contain period')

class Authors(Model):
    thesis = models.ForeignKey(thesisDB, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=200, blank=True, null=True)
    last_name = models.CharField(max_length=200, blank=True, null=True)
    middle_initial = models.CharField(max_length=2, blank=True, null=True, validators=[initial_validator])
        

`

This is the code in my forms.py `

class AuthorForm(forms.ModelForm):
    class Meta: 
        model = Authors
        exclude = ()

        widgets = {
            'first_name': forms.TextInput(attrs=
                {'placeholder': 'First Name', 'class':'form-control', 'required': 'required'}),
            'last_name': forms.TextInput(attrs=
                {'placeholder': 'Last Name', 'class':'form-control', 'required': 'required'}),
            'middle_initial': forms.TextInput(attrs=
                {'placeholder': 'M.I.', 'class':'form-control', 'required': 'required'}),
        }

AuthorFormSet = inlineformset_factory(thesisDB, Authors, form=AuthorForm, 
        fields=['first_name', 'last_name', 'middle_initial'], extra=3, can_delete=False)

class thesisForm(forms.ModelForm):

    class Meta:
        model = thesisDB
        fields = ('title', 'published_date', 'course','tags', 'abstract', 'pdf',)
        readonly_fields = ['date_created']
        course = forms.ModelChoiceField(queryset=ColCourse.objects.all().order_by('-course_name'))
#        abstract = forms.CharField(widget=CKEditorWidget())
#        problem = forms.CharField(widget=CKEditorWidget())
        widgets = {
            'title': forms.TextInput(attrs=
                {'placeholder': 'Title', 'class':'form-control', 'required': 'required'}),
            'published_date': forms.DateInput(attrs=
                {'class':'form-control', 'required': 'required', 'type':'date'}),
            'abstract': forms.Textarea(attrs=
                {'placeholder': 'Abstract', 'class':'form-control',}),
            'course': forms.Select(attrs=
                {'placeholder': 'Short Description', 'class':'regDropDown', 'required': 'required'}),
        }


    def __init__(self, *args, **kwargs):
        super(thesisForm, self).__init__(*args, **kwargs)
        # Making location required
        self.fields['pdf'].required = True
        self.fields['abstract'].required = True
        self.fields['tags'].required = True

`

And this is my views.py for submitting the form. `

@login_required
@for_students
def submission(request):
    formset = AuthorFormSet()
    if request.method == "POST":
        form = thesisForm(request.POST, request.FILES)
        if form.is_valid() and formset.is_valid():
            form.instance.uploaded_by = request.user  # set the user
            post = form.save()  # save the form
            
            formset.instance.thesis = form.instance.thesis_id
            post = formset.save()

            message = "Your project entitled %s has been submitted successfully! We will notify you through email if it is once evaluated" % form.instance.title
            messages.success(request, message)
            return redirect('/profile/personal_repository/')
    else:
        form = thesisForm()
        formset = AuthorFormSet()

    return render(request,'StudentSubmitProject.html',{'form':form, 'formset':formset})

and my html file

<div class="container-fluid profilecontainer">
  <div class="row">
    <div class="col-lg-2"></div>
    <div class="col-lg-8 right_section">
      <h4 class="textmaroon">Submit A Project</h4>
      <p>The requirements for submitting a thesis follows:<p>
      <ul>
        <li>The softcopy of your thesis which is in PDF format.</li>
        <li>The pdf file should contain the approval form attesting the thesis has been approved by your department.</li>
        <li>The descriptions of thesis such as its Title, Author, Publication Date, Course, and Keywords.</li>
        <li>The abstract text of your thesis which should match in the pdf file.</li>
      </ul>
      <p>Below is the form for submitting a thesis project. Your project would be evaluated first by the Admin Account before it can be available to access in the system, so ensure that the given details are valid to avoid possible rejection.</p>
      <hr></hr>

      <form method="POST" class="mt-5 form-group profile_form" enctype="multipart/form-data">
        {{formset.management_data }}
        {% csrf_token %}

        <h4 class="textmaroon">Add author</h4>
        <p>Enter the author/s of the thesis project</p>
        <hr></hr>
        <div class="row">
          {% for form_s in formset %}
          <div class="col-md-5">
            {{form_s.first_name | as_crispy_field}}
          </div>
          <div class="col-md-5">
            {{form_s.last_name | as_crispy_field}}
          </div>
          <div class="col-md-2">
            {{form_s.middle_initial | as_crispy_field}}
          </div>
          {% endfor %}
        </div>

        <h4 class="textmaroon mt-5">Describe the thesis</h4>
        <p>Define the thesis project</p>
        <hr></hr>
        <div class="row">
          <div class="col-md-12">
            {{form | crispy}}
          </div>
        </div>

         <div class="row">
          <div class="col-md-12">
            <button type="submit" class="btn btn-danger mt-3 float-end">Submit</button>
            <button type="reset" class="btn btn-secondary mt-3 me-2 float-end">Reset</button>
          </div>
        </div>
      </form>
    </div>
    <div class="col-lg-2"></div>
  </div>
</div>

`

My problem is that the entered data in the form saves, but not in the formset as well

because you didn't add request.POST to your formset, so no data was passed in the formset:

if request.method == "POST":
     formset = AuthorFormSet(request.POST) #need request.POST
     form = thesisForm(request.POST, request.FILES)
     if form.is_valid() and formset.is_valid():

if there is also file in the formset, add request.FILES as second arg

Back to Top