I’d like to create a “update user’s profile” page to let users modify their profiles, so I come up with the following models:
class Profile(models.Model):
user = models.OneToOneField(User)
nick_name = models.CharField(blank=True,max_length=100)
school = models.CharField(blank=True,max_length=100)
motto = models.CharField(blank=True,max_length=100)
class ProfileForm(ModelForm):
class Meta:
model = Profile
And my view is designed as:
@login_required
def update_profile_view(request):
if request.method == 'POST':
user = request.user
try:
profile = user.get_profile()
except Exception:
profile = Profile.objects.create(user=user)
form = ProfileForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
profile.nick_name = cd['nick_name']
profile.school = cd['school']
profile.motto = cd['motto']
profile.save()
return HttpResponseRedirect('/main_page/')
else:
form = ProfileForm()
return render(request, 'update_profile.html', {'form':form})
The relationship between an user and a profile is apparently 1to1, and with request I can determine the current user. So the form’s user field needn’t to be filled. Unfortunately, this couldn’t pass “the form.is_valid()” test. And it seems hard to modify a form before “is_valid” invoked. For simplicity, I don’t want to create my own Form Class, neither do I want to write customized form validation. Is there any other way to solve the problem?
Your view can be greatly simplified:
There’s no need to manually assign the fields like you’re doing. Django ORM knows how to do an insert versus an update automatically. So if you simply pass the ProfileForm an instance of a Profile, it knows to do an update. If there’s no instance of a profile, it’s going to do an insert.
Now, if you want to make the assignment of the user transparent in the UI, you’ll need to exclude the
userfield from the form and assign it yourself. There are a couple of different ways to do that.I would also recommend leveraging
reversein your redirect so you don’t have a hard-coded path.