0

I am trying to extend a user profile in django so that user can add profile photo and birthday date and I am using django-allauth for my user authentication. I am currently following a reference but for the reference a new user registration was used without involving django-allauth. I have thus implemented the codes but stock on one point where I can not figure out where to place this particular line of code

# Create the user profile
profile = Profile.objects.create(user=new_user)

below is the profile Edit code Model

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)
    date_of_birth = models.DateField(blank=True, null=True)
    photo = models.ImageField(
            upload_to= upload_location,
            null = True,
            blank = True,
            height_field = "height_field",
            width_field = "width_field")

    def __str__(self):
        return 'Profile for user {}'.format(self.user.username)

Form.py

class UserEditForm(forms.ModelForm):
    username = forms.CharField(required=True)
    email = forms.EmailField(required=True)
    first_name = forms.CharField(required=False)
    last_name = forms.CharField(required=False)

    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'username', 'email']

class ProfileEditForm(forms.ModelForm):
    """docstring for ProfileEditForm."""
    class Meta:
        model = Profile
        fields = ['date_of_birth', 'photo']

View

def edit(request):
    if request.method == 'POST':
        user_form = UserEditForm(instance = request.user, data = request.POST)
        profile_form = ProfileEditForm(instance = request.user.profile, data = request.POST, files = request.FILES)

        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()

    else:
        user_form = UserEditForm(instance= request.user)
        profile_form = ProfileEditForm(instance=request.user.profile)

   return render(request, 'account/edit.html',
    {'user_form': user_form, 'profile_form': profile_form})

and if I try to run the code like that I get an error User has no profile. any further code would be presented based on request.

Urls

url(r'^profile/edit/$', views.edit, name='update_profile'),

Template

<form method="POST" action="." class="" enctype="multipart/form-data"/>
    {% csrf_token %}
    {{ user_form.as_p }}
    {{ profile_form.as_p }}
    <input type="submit" name="submit" value="update">

</form>
King
  • 1,885
  • 3
  • 27
  • 84
  • add `urls.py` as well as `template`. – Piyush Maurya Aug 23 '17 at 16:50
  • you just need to make a profile for each user?right? you can use signals to add a profile for each user when a new user has been created. – Navid Zarepak Aug 23 '17 at 16:53
  • I have included it @PiyushMaurya – King Aug 23 '17 at 16:53
  • @Navid2zp I want users to be able to edit their profile to upload a photo since no photo upload when registering – King Aug 23 '17 at 16:55
  • did you take care of making a profile for each user? and the only problem is uploading photo? or you need to do everything including creating a profile for each user which include few field like avatar and ... ? – Navid Zarepak Aug 23 '17 at 16:57
  • add `return` statement after `profile_form.save()`, something like `return HttpResponseRedirect() #add your own redirect view`. – Piyush Maurya Aug 23 '17 at 16:58
  • @Navid2zp has it, you can add a signal handler to save a profile when a new user is created. Another option, you can monkey-patch the `User` object with a property that will fetch the profile if it exists, or create it if it does not, then use that property to load the profile in the rest of your code. – wmorrell Aug 23 '17 at 16:58
  • @Navid2zp user can sign up. that means creating an account. using django-allauth I then want to extend the ready created account to be able to create a profile which would contain users initial details with ability to alter those details (email, username, ...) and also add new fields like profile photo and birthday date – King Aug 23 '17 at 17:00
  • @PiyushMaurya that still does not solve the problem as it would reqire ` User has no profile. ` – King Aug 23 '17 at 17:02
  • i don't think you really need django-allauth to do that, you can simply do it yourself. but the problem here is that the user has no profile. like @wmorrell mentioned you can check if the profile exist and if not create one and then try to save the data. check this out too: [link](https://stackoverflow.com/questions/44820931) – Navid Zarepak Aug 23 '17 at 17:03
  • @Navid2zp I used django-allauth for my user authentication – King Aug 23 '17 at 17:04
  • @King can you see the profile for that user in your admin panel? or profile isn't even there? – Navid Zarepak Aug 23 '17 at 17:07
  • the main problem is this `profile = Profile.objects.create(user=new_user)` which I don't know where to position it – King Aug 23 '17 at 17:08
  • when you register a new user, and after you saved the new user. you can put it after you saved the user and user=your-new-user-instance – Navid Zarepak Aug 23 '17 at 17:09
  • @Navid2zp I can see it in the admin panel but using it in my template i get an error saying `User has no profile.` – King Aug 23 '17 at 17:09

2 Answers2

1

In your view, add (or add elsewhere, and import):

def load_profile(user):
  try:
    return user.profile
  except:  # this is not great, but trying to keep it simple
    profile = Profile.objects.create(user=user)
    return profile

Then change your view function to use load_profile(request.user) instead of request.user.profile.

View

def edit(request):
    profile = load_profile(request.user)
    if request.method == 'POST':
        user_form = UserEditForm(
            instance=request.user,
            data=request.POST,
        )
        profile_form = ProfileEditForm(
            instance=profile,
            data=request.POST,
            files=request.FILES,
        )

        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()

    else:
        user_form = UserEditForm(instance=request.user)
        profile_form = ProfileEditForm(instance=profile)

    return render(
        request,
        'account/edit.html',
        {'user_form': user_form, 'profile_form': profile_form}
    )
wmorrell
  • 4,988
  • 4
  • 27
  • 37
  • sorry I am confused – King Aug 23 '17 at 17:16
  • Your problem is there is no `profile` attribute on `user`. This function takes a `user` object, and tries to return the `profile`. If one does not exist (the error you are seeing), then a `DoesNotExist` exception is thrown. The function catches that exception, then creates a new profile to attach to the user, and returns that new profile. – wmorrell Aug 23 '17 at 17:38
  • okay. I understand your explanation but could you help edit your answer to include my view? – King Aug 23 '17 at 17:42
  • Ok, but it's literally just replacing `request.user.profile` with the result of calling `load_profile(request.user)` just like I said. – wmorrell Aug 23 '17 at 18:14
  • I have actually done that but the problem now is that it is not creating the profile – King Aug 23 '17 at 18:15
  • I got the error `Reverse for 'profiles' not found. 'profiles' is not a valid view function or pattern name.` – King Aug 23 '17 at 18:17
  • You will need to be more specific. `load_profile` will either return a profile that exists or return a brand new profile. What is the exact error you are seeing? – wmorrell Aug 23 '17 at 18:18
  • it was a typo graphical error it should be profile. thanks. – King Aug 23 '17 at 18:19
  • I have marked it has correct. any chance of chatting with you? – King Aug 23 '17 at 18:20
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/152664/discussion-between-wmorrell-and-king). – wmorrell Aug 23 '17 at 18:21
  • Hi I need you help regarding a question. https://stackoverflow.com/questions/46263867/creating-relationship-between-two-apps-in-django – King Sep 18 '17 at 10:06
1

As your error tells User profile doesn't exist: In your view:

def edit(request):
    if request.method == 'POST':
        profile_form = ProfileEditForm(request.POST, request.FILES)

        if profile_form.is_valid():
            instance = profile_form.save(commit=False)
            instance.user = request.user
            instance.save()
            return # add here

    else:
        profile_form = ProfileEditForm()

    return render(request, 'account/edit.html', {'profile_form': profile_form})

It will work.

Piyush Maurya
  • 1,945
  • 16
  • 26