2

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!

Carlo
  • 444
  • 4
  • 12

2 Answers2

1

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()
enes islam
  • 1,054
  • 4
  • 12
  • Thank you dear @enes, I marked as accepted since the solution#1 actually worked; however, since as you can see I am already using Signals in my pj, I'd like to implement the solution#2 better. But in that case, the signal is just not firing up (while the signal I already have in place works fine). Would you give me some hints over that? thanks! – Carlo May 25 '22 at 10:34
  • 1
    You are welcome @Carlo. Solution 2 is triggered only when a user object is updated. So you need to update User.is_active and the signal will detect the action and will run. – enes islam May 25 '22 at 11:56
  • 1
    after some trials i found out that creating signals.py aka moving signals out of models.py requires to add some code snippets ref: https://stackoverflow.com/questions/59435187/django-signals-not-working-when-placed-outside-models-py thank you! – Carlo May 26 '22 at 10:11
  • 1
    Nice to see the solution. You are welcome. Happy Hacking! – enes islam May 26 '22 at 11:12
0

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.

mesmerlord
  • 48
  • 1
  • 4