Home > Software engineering >  django form.is_valid is failing & not saving the form
django form.is_valid is failing & not saving the form

Time:06-08

My account model automatically creates when user creates a new user account & only user value is added to that model, rest remains empty! i am trying to make the user update or add more info in their account model but the is.valid() is failing in views & not saving the form. what went wrong & how to fix it?

Models.py

class profile(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    bio = models.TextField(blank=True, null=True, max_length=100)
    profile_img = models.ImageField(
        upload_to="profile_images", default="default.jpg")
    location = models.CharField(max_length=100, blank=True)

    def __str__(self):
        return self.user.username

Forms.py

class accountForm(ModelForm):
    class Meta:
        model = profile
        fields = "__all__"
        widgets = {
            # 'fields': forms.TextInput(attrs={'class': "form-control"}),
            'profile_img': forms.FileInput(attrs={'class': 'form-control', 'id': 'inputGroupFile04'}),
            'bio': forms.Textarea(attrs={'class': 'form-control'}),
            'location': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Location'}),

        }

views.py

def account(request):
    Profile = profile.objects.get(user=request.user)
    form = accountForm(instance=Profile)
    if request.method == "POST":
        form = accountForm(request.POST, instance=Profile)
        if form.is_valid():
            form.save()
            return redirect("sign_in")

    context = {"form": form}
    return render(request, "account.html", context)

CodePudding user response:

I would impliment some error handling in your view. You have an

if form.is_valid: statement but no else. That's why errors are not showing up on the page

Usually when this happens to me I drop a debugger statement right after the call to .is_valid()

import ipdb; ipdb.set_trace()

Then in the resulting terminal I will type form.errors and you should see what went wrong

CodePudding user response:

Firstly, in order to upload files, you’ll need to make sure that your element correctly defines the enctype as "multipart/form-data" in your form tag:

#templates file
<form enctype="multipart/form-data" method="post" action="/foo/">

Secondly, add request.FILES to form = accountForm(request.POST, request.FILES, instance=Profile)

You can read more about this from django docs

CodePudding user response:

You can use cleaned_data to save the form.

Try this view:

views.py


def account(request):
    profile_instance = profile.objects.get(user=request.user)
    form = accountForm(instance=profile_instance)
    if request.method == "POST":
        form = accountForm(request.POST, instance=profile_instance)
        if form.is_valid():
            user = request.user
            bio = request.POST.get('bio')
            profile_img = request.POST.get('profile_img')
            location = request.POST.get('location')

            profile.objects.create(
                user=user, bio=bio, profile_img=profile_img, location=location)
            return redirect("sign_in")
    else:
        form = accountForm()

    return render(request, "home/account.html", {'form': form})

Make sure, you are logged in and profile model does not contain two same users for working of above code, as you have made it Foreignkey.

Note: Models are written in PascalCase not smallcase, so it will be better if you name it as Profile instead of profile. Same goes for forms, better if you write AccountForm, or more better ProfileForm instead of accountForm.




Try below code, in which profile will be created directlty.

models.py


class profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    # other fields are same...

In real scenario, it will be better to make user a OneToOneField in Profile model, as one person can only have one profile, I assumed you are creating users' profile first time, rather than updating the existing profiles, so I'll not use instance in form.

views.py

def account(request):
    if request.method == "POST":
        form = accountForm(request.POST)
        if form.is_valid():
            username = request.POST.get('username')
            password = request.POST.get('password1')
            bio = request.POST.get('bio')
            profile_img = request.POST.get('profile_img')
            location = request.POST.get('location')
            created_user = User.objects.create(
                username=username, password=password)

            profile.objects.create(
                user=created_user, bio=bio, profile_img=profile_img, location=location)
            return redirect('sign_in')
    else:
        form = accountForm()

    return render(request, "home/account.html", {'form': form})

forms.py

class accountForm(ModelForm):
    username = forms.CharField(
        widget=forms.TextInput(attrs={'class': 'form-control'}))
    password1 = forms.CharField(
        widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    password2 = forms.CharField(
        widget=forms.PasswordInput(attrs={'class': 'form-control'}))

    def clean(self):
        cleaned_data = super().clean()
        p1 = cleaned_data.get('password1')
        p2 = cleaned_data.get('password2')
        if p1 != p2:
            raise forms.ValidationError('Both the passwords must match')

    class Meta:
        model = profile
        fields = ['username', 'password1',
                  'password2', 'profile_img', 'bio', 'location']
        widgets = {
            # 'fields': forms.TextInput(attrs={'class': "form-control"}),
            'profile_img': forms.FileInput(attrs={'class': 'form-control', 'id': 'inputGroupFile04'}),
            'bio': forms.Textarea(attrs={'class': 'form-control'}),
            'location': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Location'}),

        }

It will create new users' profile directly, with password validation and those users also relate to User model, so you'll not get the error of the field user in profile model must be an user instance.

  • Related