Carlo
Carlo

Reputation: 534

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:

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!

Upvotes: 2

Views: 908

Answers (2)

enes islam
enes islam

Reputation: 1120

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()

Upvotes: 1

mesmerlord
mesmerlord

Reputation: 48

In your "post" function, you're using the same user resource. i.e "self.request.user" and "request.user" is the same thing.

You should instead be doing a Profile.objects.get(user = request.user) and changing the is_active flag there.

Upvotes: 0

Related Questions