Search code examples
djangodjango-modelsdjango-viewsdjango-templatesdjango-permissions

Access editing profile only by profile owner using UserPassesTestMixin showing error?


i have managed to create profile pages for each user and every user should edit their own profile. in model, i have used AbstractUser model. and for the editing access i have imported UserPassesTestMixin.

here is my models.py:

class Profile(AbstractUser):
    
    name=models.CharField(max_length=30, blank=True)
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birthdate = models.DateField(null=True, blank=True)

here is my views.py:

class ProfileDetailView(DetailView):
    template_name='profile.html'
    model=Profile
    def get_user_profile(self,pk):
        return get_object_or_404(Profile,pk=pk)
    

class ProfileEditView(LoginRequiredMixin,UserPassesTestMixin,UpdateView):
    model=Profile
    template_name='profile_edit.html'
    fields=['name','bio','birthdate','location','gender',]
    login_url='login'
    success_url = reverse_lazy('home')
    def get_user_profile_edit(self,pk):
        return get_object_or_404(Profile,pk=pk)

    def test_func(self):
        obj = self.get_object()
        return obj.username == self.request.user

    

the problem is when the logged in user wants to edit it's profile it is showing 403 forbidden. no user can edit their profile. in test function what should is use to fix that?


Solution

  • Since the Profile is the user model, it means that obj should be request.user:

    class ProfileEditView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
        model=Profile
        template_name='profile_edit.html'
        fields=['name','bio','birthdate','location','gender',]
        login_url='login'
        success_url = reverse_lazy('home')
        
        def get_user_profile_edit(self,pk):
            return get_object_or_404(Profile,pk=pk)
    
        def test_func(self):
            return self.get_object() == self.request.user

    You however do not per se need this, you can simply use request.user as the object itself:

    class ProfileEditView(LoginRequiredMixin, UpdateView):
        model=Profile
        template_name='profile_edit.html'
        fields=['name','bio','birthdate','location','gender',]
        login_url='login'
        success_url = reverse_lazy('home')
        
        def get_object(self, *args, **kwargs):
            return self.request.user

    In that case the view does not need a primary key, since people that visit the view will simply see their own profile to edit.