2

In the Django 2.2 docs , it states the following :

"is_active " is a Boolean. Designates whether this user account should be considered active. We recommend that you set this flag to False instead of deleting accounts; that way, if your applications have any foreign keys to users, the foreign keys won’t break.

My question is this, If I had a website, and I gave my users the ability to delete their own accounts by following this practice, wouldn't my database be filled with non-active accounts once my website gains a bit of traffic?

What would be the best method to letting users ( without staff or super user status ) on your website delete their own accounts properly in Django 2.2 ?

Thank you in Advance for any Help

e rosario
  • 29
  • 5
  • Why would that be a problem. A database uses an index to fast retrieve data. So even if there is a large amount of "dead data", that will not have a significant impact on the performance. – Willem Van Onsem Dec 18 '20 at 23:19
  • The idea is that if you remove a user, and you have a `Post` with a `ForeignKey` to `User`, then it will thus remove all posts, which might not be the intention. – Willem Van Onsem Dec 18 '20 at 23:19
  • 2
    Also consider that if you provide an option that says "delete" and you just mark the account inactive, the user will expect their data to be gone & it's not. This would be a problem with European users due to GDPR. – markwalker_ Dec 18 '20 at 23:30
  • You can check the inactive users in a certain period of time. – Willy satrio nugroho Dec 19 '20 at 06:42

1 Answers1

2

My question is this, If I had a website, and I gave my users the ability to delete their own accounts by following this practice, wouldn't my database be filled with non-active accounts once my website gains a bit of traffic?

Eventually, yes. The question is, Why is that a problem?. Databases normally construct indexes on primary keys, so that means that it can often retrieve the user of a given post object often efficiently, even if there is a certain amount of "dead data".

The main problem with deleting a user is that there are often triggers that will remove all the related data. Indeed, imagine that you have a Post model:

from django.conf import settings

class Post(models.Model):
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )

This means that if you delete a user, it will remove all Post objects where that user is the author, and not only for Posts of course, but everything you link to that user with a CASCADE trigger. This might not be the intended effect. Often you want to keep the data the user has constructed, unless for example the user (explicitly) asks this.

You can define views to let people delete their account, either as a "soft" delete (with .is_active set to False), or a "hard" delete (remove the object, and let the triggers ripple). You can make views like:

# soft delete
from django.contrib.auth import logout as auth_logout, get_user_model
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods

@login_required
@require_http_method(['POST'])
def remove_account(request):
    user_pk = request.user.pk
    auth_logout(request)
    User = get_user_model()
    User.objects.filter(pk=user_pk).update(is_active=False)
    # …
    # return HTTP response

or a hard delete:

# hard delete
from django.contrib.auth import logout as auth_logout, get_user_model
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods

@login_required
@require_http_method(['POST'])
def remove_account(request):
    user_pk = request.user.pk
    auth_logout(request)
    User = get_user_model()
    User.objects.filter(pk=user_pk).delete()
    # …
    # return HTTP response

and in the template a button to remove the account:

<form method="post" action="{% url 'name-of-delete-view' %}">
    {% csrf_token %}
    <button type="submit">delete account</button>
</form>

with name-of-delete-view the name you have given to the view in the path(…, name=…) or re_path(…, name=…).

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555