Django-profiles custom create/edit modelForm not saving properly
Summary:
u = self.instance.user
in
def save(self, *args, **kwargs):
u = self.instance.user
u.first_name = self.cleaned_data['first_name']
u.last_name = self.cleaned_data['last_name']
u.save()
return super(ProfileForm, self).save(*args, **kwargs)
is causing a problem because self.instance doesn't exist. But yet this is how it is done in other examples, where it seems to work. What am I missing?
Read on for more info ->
I am using both django-registration and django-profiles. For the purposes of just getting it to work, I have not added any extra fields to the profile model (the one that extends User). So far it looks like this:
class sumaConnectUser(models.Model):
user = models.ForeignKey(User)
def __unicode__(self):
return self.user.first_name + " " + self.user.last_name
def get_absolute_url(self):
return ('profiles_profile_detail', (), { 'username': self.user.username })
get_absolute_url = models.permalink(get_absolute_url)
My understanding is as of now, my user "profile" should just include the fields that come with the contr开发者_开发问答ib.auth model User. ( first name, last name etc)
In my urls.py, I pass in my custom form for the creation and edit of the profiles-
(r'^profiles/edit', 'profiles.views.edit_profile', {'form_class': ProfileForm, }),
(r'^profiles/create', 'profiles.views.create_profile', {'form_class': ProfileForm, }),
(r'^profiles/', include('profiles.urls')),
Finally, here is my profile form-
from suma.sumaconnect.models import sumaConnectUser
from django import forms
from django.contrib.auth.models import User
class ProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
try:
self.fields['first_name'].initial = self.instance.user.first_name
self.fields['last_name'].initial = self.instance.user.last_name
except User.DoesNotExist:
pass
first_name = forms.CharField(label="First Name")
last_name = forms.CharField(label="Last Name")
class Meta:
exclude = ('user',)
model = sumaConnectUser
def save(self, *args, **kwargs):
u = self.instance.user
u.first_name = self.cleaned_data['first_name']
u.last_name = self.cleaned_data['last_name']
u.save()
return super(ProfileForm, self).save(*args, **kwargs)
My goal is to allow the user to edit their first name and last name as part of the profile edit, but not their username and password.
I thought about replacing
u = self.instance.user
with
u = User.objects.get(user = self.cleaned_data['username'])
but this would require me to include a username = forms.CharField on the page which I do not want to display. As far as I understand, when I come to the create profile or edit profile page, I should be automatically editing the profile associated with the user which I am logged in as.
By the time I come to this create or edit user page, the user model already exists, but the profile doesn't. Is this the cause of the problem? I think I am misunderstanding something major, and I would greatly appreciate any pointers as to where I am going wrong. Thanks!
You can copy fields over if you like, and dual-update them as you have in the above, but that's not the purpose of the profile. It's supposed to handle fields not in the original auth.User, since you shouldn't need to edit that model directly. You mentioned "extending User" above - you aren't actually inheriting from auth.User, are you? I highly don't recommend that.
Update:
See this reference material. It is using the same syntax as you to do user-updating inside the profile.
Update 2:
The example is for edit profile, not create profile. Looking at the code in profile.views.create_profile:
if request.method == 'POST':
form = form_class(data=request.POST, files=request.FILES)
if form.is_valid():
profile_obj = form.save(commit=False)
profile_obj.user = request.user
profile_obj.save()
So it saves the form first, then sets user, then saves the profile.
That means you can't set the user values in the form.save, you need to do it in the profile's model.save:
# in sumaConnectUser:
from django.db.models.base import ObjectDoesNotExist
class sumaConnectUser(models.Model):
...
def save( self, *args, **kwargs ):
s = super(sumaConnectUser,self).save( *args, **kwargs )
try:
u = s.user
u.first_name = self.first_name
u.last_name = self.last_name
u.save()
except ObjectDoesNotExist:
pass
return s
Basically, by looking at the code in profile.views.create_profile, we are positive that it eventually calls save on the profile after it has set user
. It might not be the first time, so we need to trap that case and forget about it. Because eventually, it'll get called and trigger our save-to-user code. The upshot is that no matter what forms you have in the future for this user-profile, it'll always save back to the underlying user.
精彩评论