1

I am stumped!

I am building a form that allows the user to fill in profile fields and user fields at the same time. There are examples all over the web for this and a number on this site (eg How to create a UserProfile form in Django with first_name, last_name modifications?)

however, try as i might, i keep on getting a none type user in my form.py

some code: forms.py

class ProfileForm(ModelForm):
first_name = forms.CharField(label="First name")
last_name = forms.CharField(label="Last name")

def __init__(self, *args, **kwargs):
    super(ProfileForm, self).__init__(*args, **kwargs)
    print self.instance #profile does not exist here 
    self.fields['first_name'].initial = self.instance.user.first_name
    self.fields['last_name'].initial = self.instance.last_name

def save(self, *args, **kwargs):
    super(ProfileForm, self).save(*args, **kwargs)
    self.instance.user.first_name = self.cleaned_data.get('first_name')    
    self.instance.user.last_name = self.cleaned_data.get('last_name')
    self.instance.user.save()

class Meta:
    model = UserProfile
    exclude = ('user')

urls.py

    url(r'^profiles/edit/', 'profiles.views.edit_profile', {'form_class': ProfileForm}, name='edit_profile' ),

template.html

    <div class="clearfix">
    <legend>Edit your profile details</legend>
</div>
{% include 'profiles/profile_form.html' with user=user %}

the view is coming from django-profiles, but i have even tried pulling into an app and seen that my user exists and is being pulled into an instance in the view, the instance is devoid of user in the form!

other things of note: i am using email as my authentication method other than username, but still have a text based random username (because i understand there are issues with emails as usernames in django-profiles). Could this still be my issue?

if its helpful, here is my authenticate def:

    def authenticate(self, username=None, password=None):
    """ Authenticate a user based on email address as the user name. """
    try:
        user = User.objects.get(email=username)
        if user.check_password(password):
            return user
    except User.DoesNotExist:
        return None 

def get_user(self, user_id):
    """ Get a User object from the user_id. """
    try:
        return User.objects.get(pk=user_id)
    except User.DoesNotExist:
        return None

this is references as a custom backend, and i have confirmed that it works.

I hope someone has some insight!

Edits:

my full exception:

Exception Type: TemplateSyntaxError
Exception Value: Caught AttributeError while rendering: 'NoneType' object has no attribute 'first_name'
Exception Location:/Users/willcadell/placespeak/webapps/place/../place/accounts/forms.py in __init__, line 13

view (from django-profiles):

def edit_profile(request, form_class=None, success_url=None,
             template_name='profiles/edit_profile.html',
             extra_context=None):

    try:

        profile_obj = request.user.get_profile()
        print profile_obj #profile is good here
    except ObjectDoesNotExist:
        return HttpResponseRedirect(reverse('profiles_create_profile'))

    if success_url is None:
        success_url = reverse('profiles_profile_detail', kwargs={ 'username': request.user.username })
    if form_class is None:
        form_class = utils.get_profile_form()      
    if request.method == 'POST':
        form = form_class(data=request.POST, files=request.FILES, instance=profile_obj)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(success_url)
    else:
        form = form_class(instance=profile_obj)

    if extra_context is None:
        extra_context = {}

    context = RequestContext(request)

    for key, value in extra_context.items():
        context[key] = callable(value) and value() or value

    return render_to_response(template_name,
                          { 'form': form,
                          'profile': profile_obj,},
                          context_instance=context)

I have also added two comments indicating where the profile exists and where it does not, ie it is in the view as profile_obj but does not appear in the form as self.instance.

Another (possibly unrelated) symptom is that for this exception page, django toolbar does not show up... weird!

Community
  • 1
  • 1

2 Answers2

1

You might not always have an instance, that may be the reason it shows as None. Try to do

def __init__(self, *args, **kwargs):
    super(UserProfileForm, self).__init__(*args, **kwargs)
    if kwargs.has_key('instance'):
        instance = kwargs['instance']
        self.initial['first_name'] = instance.first_name
        self.initial['last_name'] = instance.last_name

Also, you are using the first_name from the user object but the last_name from the user_profile object! I would just be consistent. I'm using the code below to make them available from both locations

   # first_name - stores in auth.User
    def _get_first_name(self):
        return self.user.first_name
    def _set_first_name(self, name):
        self.user.first_name = name
    first_name = property(_get_first_name, _set_first_name)

    # last_name - stores in auth.User
    def _get_last_name(self):
        return self.user.last_name
    def _set_last_name(self, name):
        self.user.last_name = name
    last_name = property(_get_last_name, _set_last_name)
Meitham
  • 9,178
  • 5
  • 34
  • 45
  • Thanks Meitham! i actually ended up rewriting the view completely. Thereby addressing my silly mistake regarding first_ and last_name (great spot!) I also ended up setting the initial data values in the view instead. – Will Cadell Feb 19 '12 at 22:53
  • Meitham, I'd give you a +1, if i had the reputation :( – Will Cadell Feb 19 '12 at 22:57
0

This is what i ended up doing:

view.py:

def edit_profile(request):

profile_obj = request.user.get_profile()
print dir(profile_obj.profileasset_set)
asset_obj = profile_obj.
user_obj = request.user

if request.method == 'POST':
    form = ProfileForm(request.POST, )
    if form.is_valid():

        profile_obj.twitter = form.cleaned_data['twitter']
        profile_obj.about = form.cleaned_data['about']
        profile_obj.url = form.cleaned_data['url']
        profile_obj.save()

        profile


        user_obj.first_name = form.cleaned_data['first_name']
        user_obj.last_name = form.cleaned_data['last_name']
        user_obj.save()

        form.save()
        return HttpResponseRedirect('/profiles/profile')

else:
    form = ProfileForm(instance=user_obj, 
        initial={
                 'first_name':user_obj.first_name,
                 'last_name':user_obj.last_name,
                 'twitter':profile_obj.twitter,
                 'url':profile_obj.url,
                 'about':profile_obj.about,
                }
        )

template = 'profiles/edit_profile.html'
data = {'form': form, }      
return render_to_response(template, data, context_instance=RequestContext(request))

forms.py:

class ProfileForm(ModelForm):

first_name = forms.CharField(label="First name")
last_name = forms.CharField(label="Last name")
twitter = forms.CharField(label="Twitter")
about = forms.CharField(label="About", widget=forms.Textarea)
url = forms.CharField(label="URL")

class Meta:
    model = UserProfile
    fields = ('url', 'twitter', 'about')

hope this helps someone!