1

I am trying to retrieve information regarding a user's profile to display on a page. The issue is it retrieves the relevant information from every user instead of just the one logged in.

I have tried requesting for only the user logged in at the time, but I unfortunately could not get it to work.

HTML

    <div>
        <span class="bold">
            <p>Bio:</p>
        </span>
        <p>
            {{ profile.bio }}
        </p>
    </div>

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, default=None, null=True, on_delete=models.CASCADE)
    bio = models.CharField(max_length=2000)
    instrument = models.CharField(max_length=255, choices=instrument_list, blank=True)
    level = models.CharField(max_length=255, choices=level_list, blank=True)
    preferred_language = models.CharField(max_length=255, choices=language_list, blank=True)
    time_zone = models.CharField(max_length=255, choices=time_list, blank=True)

    def __str__(self):
        return self.profile

    @receiver(post_save, sender=User)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            Profile.objects.create(user=instance)

    @receiver(post_save, sender=User)
    def save_user_profile(sender, instance, **kwargs):
        instance.profile.save()

class ProfileForm(ModelForm):
    class Meta:
        model = Profile
        exclude = ('user',)

views.py

@login_required
def profile_page_edit(request):
    if request.method == 'POST':
        form = ProfileForm(request.POST)

        if form.is_valid():
            profile = form.save(commit=False)
            profile.user = request.user
            profile.save()
            return redirect('/student/profile-page')

        else:
            form = ProfileForm()

    form = ProfileForm()

    context = {'form': form }
    return render(request, 'student/profile_page_edit.html', context)

@login_required
def profile_page(request):
    form = ProfileForm
    profile = request.user.profile
    args = {'form' : form, 'profile' : profile}
    return render(request, 'student/profile_page.html', args)

I am trying to get the profile_page view to display the relevant model information for only one user (the one currently logged in).

  • do you need to show data in forms or html files? – shafik Jan 27 '19 at 15:11
  • I don't understand why you are passing `Profile.objects.all()` to the template and iterate over it. What else but **all** the `Profile`s would you expect? The currently logged in user is `request.user` so just use that. – Fynn Becker Jan 27 '19 at 15:12
  • 1
    Do not delete your question when you get your answer. See https://meta.stackoverflow.com/questions/378440/caveat-emptor-making-students-aware-they-cannot-delete-their-homework-questions. –  Jan 27 '19 at 15:26

1 Answers1

3

You need to filter the queryset, and thus fetch the correct one:

from django.contrib.auth.decorators import login_required

@login_required
def profile_page(request):
    form = ProfileForm()
    profile = request.user.profile
    context = {'form' : form, 'profile' : profile}
    return render(request, 'student/profile_page.html', context)

in the template, we then of course only render the bio of the profile variable:

 <!-- Bio -->
    <div>
        <span class="bold">
            <p>Bio:</p>
        </span>
        <p>
            {{ profile.bio }}
        </p>
    </div>

Note that, unless you create a Profile object for that user, there is no Profile object associated with that User.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Makes sense, I was under the assumption that linking the user model would have been sufficient enough. Could you provide me with an example or redirect me on creating a profile object for a user. –  Jan 27 '19 at 15:44
  • You can call `Profile.objects.create(user=my_user, bio="it's complicated", instrument='theremin')`, etc. But note that, due to the `OneToOneField`, you can of course only create *one* `Profile` *per* user. – Willem Van Onsem Jan 27 '19 at 15:47
  • Got you. Would I write that under a model function, form, or view? –  Jan 27 '19 at 15:48
  • Well the creation is typically done in a view or signal handler. This can be through a statement like above, but a `ModelForm` can do the trick as well. That depends on when/where you want to create the `Profile`. – Willem Van Onsem Jan 27 '19 at 15:50
  • I have done that and was wondering if instead of bio="it's complicated", I could do bio=bio, to retrieve what the user enters into the form. Also, I had to add Null=True in my profile model for the user field, and now I am getting an error saying user has no profile for my "profile = request.user.profile" you instructed me to put –  Jan 27 '19 at 16:02
  • @commerce: by using a `ModelForm`, you can let the `ModelForm` do that for you, you can *exclude* the `user` and patch that later in the view. See for example [here](https://stackoverflow.com/questions/8466768/using-request-user-with-django-modelform). – Willem Van Onsem Jan 27 '19 at 16:04
  • I have updated my code above to show the changes made. I am receiving the error, "User has no profile." Also, thank you for all your help so far, it's extremely appreciated! –  Jan 27 '19 at 16:18
  • That is because for the logged in user there is no `Profile`. You probably should remove the `form = ProfileForm()` in the `else` clause, since then the errors will not show up. – Willem Van Onsem Jan 27 '19 at 16:21
  • Okay, I am trying to get rid of the errors so I can create a profile for the logged in user. I tried removing the form = ProfileForm(), but the error remained. –  Jan 27 '19 at 16:25
  • @commerce: yes, did you *create* a profile for your user? If not, then the error will persist. – Willem Van Onsem Jan 27 '19 at 16:27