Search code examples
pythondjangodjango-class-based-views

Correct way to deactivate user and its profile in Django


I have created a view where the logged-in user should be able to deactivate its profile.
I expect then to see the change being reflected in my admin section, but it's not.
Looks like the user is being deactivated but the user.profile isn't.
I am puzzled since, after I did a whole project following Django docs, the way to properly manage user deactivation seems missing.
I'd like to stay strict to Class-Based-Views.

My actual code:

# models.py

# Model to handle user profiles
class Profile(models.Model):
    """Create user profiles and manage their attributes"""
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(max_length=180, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)
    avatar = models.ImageField(upload_to='social/static/social/avatars/', null=True, blank=True) 
    follows = models.ManyToManyField('self', related_name='followed_by', symmetrical=False, blank=True)
    is_active = models.BooleanField(default=True)
    
    def __str__(self):
        return self.user.username

# Signal function to create a profile when a user is created
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        user_profile = Profile(user=instance)
        user_profile.save()

# views.py
class ProfileInactive(View):
"""User can made its profile unactive"""
model = models.Profile
template_name = 'social/profile_delete.html'

# Users can delete only their profile, or get a 404 error
def get_queryset(self):
    owner = self.request.user
    return self.model.objects.filter(user=owner)

def get(self, request, username):
    profile = get_object_or_404(models.Profile, user__username=self.kwargs['username'])
    return render(request, self.template_name, {'profile': profile})

def post(self, request, username):
    owner = self.request.user
    profile = request.user
    print(owner, profile)
    if owner == profile:
        profile.is_active = False
        owner.is_active = False
        profile.save()
        owner.save()
        logout(request)
    else:
        raise Http404
    return redirect('social:register')

and the related url path:

path('profile_delete/<str:username>/', login_required(views.ProfileInactive.as_view()), name='profile_delete'),

The issue is that:

  • After, apparently successfully, the user is being deactivated, the flag on its profile in the django admin section is still there, so like it's active, but the user cannot login anymore (like it isn't active anymore).

Example:
{{ profile.user.is_active }} shows False
{{ profile.is_active }} Shows True

I tried many combinations but not able to sort it out.

Also, I'd like to know if there's a pythonic way of managing what I expect to be a very common \ needed feature in any django application.

Thanks for any hints you may give me!


Solution

  • owner and profile is request.user.

    Solution #1

    in your model add related_name:

    class Profile(models.Model):
        user = models.OneToOneField(User, on_delete=models.CASCADE,related_name="profile")
    

    in your ProfileInactive.post method:

    def post(self, request, username):
        owner = self.request.user
        profile = request.user.profile #+
        print(owner, profile)
        if owner == profile:
            profile.is_active = False
            owner.is_active = False
            profile.save()
            owner.save()
            logout(request)
        else:
            raise Http404
        return redirect('social:register')
    

    Solution #2

    Using signals.

    create signals.py file. add this snippet:

    from django.db.models.signals import post_save
    from django.dispatch import receiver
    from django.contrib.auth.models import User
    
    @receiver(post_save,sender=User)
    def update_profile(sender, instance, *args, **kwargs):
        user= instance
        profile = user.profile
        if user.is_active == False:
             profile.is_active = False
             profile.save()
        else:
             profile.is_active = True
             profile.save()