Django NOT NULL constraint failed userprofile.user_id in case of uploading a file

Keep the user out of the form and add it on save:

if form.is_valid():
    profile = form.save(commit=False)
    profile.user = request.user
    profile.save()

I must say your model looks a bit odd; you have multiple profiles for each user, each with a single upload. Seems more likely you want a single profile, with a OneToOne relationship to User, than a separate Uploads model with a ForeignKey to UserProfile.


I added the user field to the forms.py worked:

This probably also opens up a security hole, because you could then set the user from outside of your application, overriding the logged-in user.

After digging a lot I noticed someone suggested the reason for the error is because the user is not included anyhow in the process of posting the form.

You figured that quite right. If the user is not a field, the form never knows how to fill the user field of UserProfile. Since you cannot save a UserProfile without a filled in user foreign key, you get the error.

There are various ways around this:

One way to solve the problem is to use save(commit=False) on the form, patch the user into the unsaved instance and manually saving the object to the database:

if form.is_valid():
    profile = form.save(commit=False)
    profile.user = request.user
    profile.save()

This slightly violates the encapsulation because you now handle the database save outside of the form.

You are also able to provide a initial "template" instance to the form:

form = UserProfileForm(
   request.POST,
   request.FILES,
   instance=UserProfile(user=self.request.user)
)

You probably want to do so, anyway because the form also allows to edit an existing userprofile. Currently you are saving a new UserProfile each time and since user is not unique=True in your model class, you will get multiple profiles per user. If you do not want this to be possible, check Daniel Roseman's answer, because then you probably want UserProfile.user to be a OneToOne field.

In this case, we can simplify to

profile, created = UserProfile.objects.get_or_create(user=request.user)
form = UserProfileForm(
    request.POST,
    request.FILES,
    instance=profile
)

Note also that I removed the or None as it is not necessary. BaseForm (which ModelForm derives from) does this check for you (it actually does self.data = data or {}) which essentially undoes the prior none-ification)

Tags:

Python

Django