0

I've been trying to create a method to upload a profile picture for a user at the time of registration. In order to do so, I created a custom ModelForm with a file field and displayed this along with a UserCreationForm. However, it throws this error

ValueError at /signup
The UserProfile could not be created because the data didn't validate.

Files :-

models.py

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):

    user=models.OneToOneField(User, on_delete=models.CASCADE)
    img=models.FileField(upload_to="profile/")

    def __str__(self):

        return self.user.username

forms.py

from django import forms
from . models import UserProfile
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
# Create your models here.

class ImgForm(forms.ModelForm):

    class Meta:
        model=UserProfile
        fields=['img']

urls.py

from django.urls import path 
from . import views 

urlpatterns = [

    path('', views.signin, name="signin"),
    path('signup', views.signup, name="signup"), 
    path('logout', views.logout, name="logout")


]

views.py

from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.contrib import auth
from django.http import HttpResponse
from .forms import ImgForm
from django.contrib.auth.forms import UserCreationForm
# Create your views here.

def signup(request):

    if request.method == 'POST':

        form=UserCreationForm(request.POST)
        imgform=ImgForm(request.POST, request.FILES)

        if form.is_valid() and imgform.is_valid():

            #looks good

            user = form.save()
            img=imgform.save()
            img.user=user

            return redirect('/')

        else:

            html = "<html><body><script>alert('Invalid form')</script></body></html>"
            return HttpResponse(html)

    else:

        form=UserCreationForm()
        imgform=ImgForm()
        context={

            'form':form, 
            'imgform':imgform
        }

        return render(request, "register/signup.html", context)

Form HTML Code (Signup.html)

            <div class="card-body">
                    <h1>Sign Up</h1>
                    <form action="{% url 'signup' %}" method="POST">
                    {% csrf_token %}

                    {{form.as_p}}
                    {{imgform.as_p}}
                    <div class="row">

                        <div class="col-4 text-right">
                        <input type="submit" class="btn btn-primary" value=" Sign Up " />
                        </div>
                    </div>
                </form>
                </div>

What I've tried :

Tried removing the imgform validity check (removed imgform.is_valid()) in views.py, removed all instances of imgform and the form submitted with no issues (without the image ofcourse). So my best guess is the error is caused due to saving imgform incorrectly. Couldn't figure out the problem myself. Any sort of help is appreciated!

Thanks.

Nived Sanil
  • 53
  • 1
  • 8
  • Have you tried using ImageField instead of FileField? – dfundako Mar 24 '20 at 15:18
  • Hey @dfundako, just tried this out right now. Ran into the same error again :( – Nived Sanil Mar 24 '20 at 15:22
  • What is the form validation error? In your html you send back, include `{{ form }}` in it for debugging purposes. It should render the validation errors for the form. – schillingt Mar 24 '20 at 15:32
  • @schillingt I've put up the form html code now. The form is rendered perfectly on the front end, but gives me back an 'Invalid Form' JavaScript alert on clicking submit. According to the code I've written the page returns an invalid form alert if it fails the validity check (Check views.py) – Nived Sanil Mar 24 '20 at 16:07
  • You need to see what validation errors are on the form after failing `if form.is_valid()`. – schillingt Mar 24 '20 at 16:14
  • How do I check errors? Doesn't display anything on the page as well as in the console when I submit the form. – Nived Sanil Mar 24 '20 at 16:17
  • @NivedSanil As your `UserProfile` model has OneToOne relationship with your `USER`. In POST method handling currently your second form doesn't contain any referencing with your `USER`, that's why it is showing Invalid: Field required error. You have to pass your user instance in ImgForm then it will work. [This one](https://stackoverflow.com/a/60708034/8601641) is my solution. I hope this will help you. – k33da_the_bug Mar 25 '20 at 03:47
  • @k33da_lets_debug , I tried adding a 'user' field to ImgForm in forms.py but now it renders a drop down in the sign up form with a list of all registered users which is not what I want. You've created a formset in the answer you showed, I've not worked with formsets. Is it necessary to implement this functionality? – Nived Sanil Mar 25 '20 at 04:44
  • @NivedSanil dropdown is showing because second form has user field which is `ForeignKey` field. If you don't want formset then One trick for this is you can specify `HiddenFormInput` inside your `Form` or `ModelForm` and in views pass instance of user to second form whenever both form gets post, however you need to write more code for checking is user has posted both forms or not etc which will be hassle. Using formset it will be a cleaner and maintainable approach. Whenever I need to user more than 1 form I always prefer formsets. It will surely work. You just have to change little code. – k33da_the_bug Mar 25 '20 at 05:15
  • @k33da_lets_debug Even if I keep the form field hidden, it is a compulsory field and a value needs to be sent when I submit the form. This is a sign up form. I need to create a new member after sign up. How do I do this? did I understand it wrong? Can you show what you're trying to say modifying the code I've posted above? thanks. – Nived Sanil Mar 25 '20 at 06:19
  • @NivedSanil Modifying means you just have to replace some of my code with your Models and Forms. That code is exactly made for sign up. However it takes all the details from user while performing sign up(i.e both forms get filled at sign up). If you want to create user first and then take his/her details when he logs in still that code will work as you just have to get the current user details and pass it as instance to the formset. About that compulsory field you have to pass some initial value before processing it(form has `initial` parameter to specify initial values for some fields). – k33da_the_bug Mar 25 '20 at 06:26
  • I did not understand what I've to change and what needs to be kept with your example. It would help me a ton if you add an answer with the changes. I'm extending a UserCreationForm here so I'd prefer not using a separate model for the user. Thanks for your input. – Nived Sanil Mar 25 '20 at 06:42

0 Answers0