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 inPascalCase
notsmallcase
, so it will be better if you name it asProfile
instead of. Same goes for forms, better if you writeprofile
AccountForm
, or more betterProfileForm
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
.