ModelForm.save() raises IntegrityError

Within a TestCase, I’m attempting to create a model instance as the result of calling .save() on a ModelForm within TestCase.setUpTestData. However I get the following error: django.db.utils.IntegrityError: NOT NULL constraint failed: photos_photo.photographer_id. As shown in the test a User is attached, so I’m not sure why this error is still being raised?

test_forms.py

class RedundantImageUpload(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.test_image = SimpleUploadedFile(
            "test_image.jpg",
            content=b'''GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00
            \x00ccc,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00''',
            content_type="image/gif"
        )
        user = User.objects.create_user("User")

        form = PhotoForm({'title': "Image Title"}, {'source': cls.test_image})
        form.save(commit=False)
        form.photographer = user
        form.save()

        cls.submitted_form = PhotoForm(
            {"title": "Image Title"},
            {"source": cls.test_image}
        )

    def test_image_upload_path_exists(self):
        with self.assertRaisesMessage(ValidationError, "Image already uploaded: test_image.jpg"):
            self.submitted_form.errors

forms.py

from django import forms
from django.core.exceptions import ValidationError
from django.core.files.storage import get_storage_class

from .models import Photo

def validate_title(value):
    title = value.strip()
    if not title:
        raise ValidationError("Must provide image title", code="blank_image_title")

class PhotoForm(forms.ModelForm):
    title = forms.CharField(strip=False, validators=[validate_title])

    def clean_source(self):
        stored_user_uploads = get_storage_class()()
        file_name = self.cleaned_data["source"].name
        if stored_user_uploads.exists(file_name):
            raise ValidationError(f"Image already uploaded: {file_name}")
        return self.cleaned_data["source"]


    class Meta:
        model = Photo
        fields = ["source", "title"]

models.py

from django.db import models
from django.conf import settings

# Create your models here.
class Photo(models.Model):
    source = models.ImageField(upload_to='uploads/%Y/%m/%d/')
    title = models.CharField(max_length=50)
    upload_date = models.DateField(auto_now_add=True)
    likes = models.IntegerField(default=0)
    photographer = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )

    def __str__(self):
        return self.title

Not quite - when you issue the form.save(commit=False), the return value from that method is the instance of the object being created from the form.

You’re looking to do something closer to this:

        form = PhotoForm({'title': "Image Title"}, {'source': cls.test_image})
        photo = form.save(commit=False)
        photo.photographer = user
        photo.save()