From 9f5fa60ca0cd05f0e956c4a24190978ce3175ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 7 Oct 2026 11:21:38 +0200 Subject: [PATCH] docs: explain manual disconnection and Django user deletion Show how to remove social account associations in code, explain which pipeline steps direct deletion bypasses, and clarify cascading user deletion and unrelated foreign key errors. Correct the storage API signature and link the guidance from the logout documentation. Fixes python-social-auth/social-app-django#242 --- docs/configuration/django.rst | 49 +++++++++++++++++++++++++++++++++++ docs/logging_out.rst | 3 +++ docs/pipeline.rst | 2 ++ docs/storage.rst | 4 +-- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/docs/configuration/django.rst b/docs/configuration/django.rst index d9a0cba6..78c68438 100644 --- a/docs/configuration/django.rst +++ b/docs/configuration/django.rst @@ -164,6 +164,55 @@ Django user. It is not a separate authentication user model. By default, ``UserSocialAuth.user`` references ``settings.AUTH_USER_MODEL``, so social login and Django's username/password login use the same user model. +.. _django-manual-disconnection: + +Disconnecting social accounts in code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With the default Django ORM storage, you can remove social account associations +directly through the user's ``social_auth`` related manager. Given a saved +Django ``user`` instance:: + + # Remove all social account associations for this user. + user.social_auth.all().delete() + + # Remove only this user's GitHub associations. + user.social_auth.filter(provider="github").delete() + +These operations preserve the Django user and application data related only +to that user. Application models that reference ``UserSocialAuth`` follow +their own relationship's ``on_delete`` behavior: ``CASCADE`` deletes dependent +rows, while ``PROTECT`` or ``RESTRICT`` can prevent deletion. Check those +relationships before removing associations. + +To remove a single association using the storage API:: + + from social_django.models import UserSocialAuth + + association = user.social_auth.get(pk=association_id) + UserSocialAuth.disconnect(association) + +Direct deletion bypasses the :ref:`disconnection-pipeline`, including the check +that the user has another login method, optional provider token revocation, +and any custom pipeline steps. Use it when your application intentionally +handles these responsibilities itself. For user-facing disconnection, use the +normal disconnection view so the configured pipeline runs. + +Deleting a Django user +^^^^^^^^^^^^^^^^^^^^^^ + +The ``UserSocialAuth.user`` foreign key uses ``on_delete=models.CASCADE``. +Deleting a user through Django's ORM, for example with ``user.delete()``, +automatically deletes their social account associations. You do not need to +disconnect those associations in a user-deletion hook first. Cascading deletion +does not run the disconnection pipeline or revoke provider tokens. + +Other application models that reference the user follow their own deletion +rules. If user deletion raises a foreign key error naming another application's +table, inspect that model's relationship, migrations, and deletion code. +Removing social account associations does not remove references from unrelated +tables. + Custom authentication user models ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/logging_out.rst b/docs/logging_out.rst index d0b50f95..39a20624 100644 --- a/docs/logging_out.rst +++ b/docs/logging_out.rst @@ -27,5 +27,8 @@ check that the user account is in a valid state for disconnection (it has at least one more social account associated, or a password, etc). This behavior can be overridden by changing the `Disconnection Pipeline`_. +For Django code that removes associations directly, and for user deletion, +see :ref:`django-manual-disconnection`. + .. _logout_user(): https://github.com/maxcountryman/flask-login/blob/a96de342eae560deec008a02179f593c3799b3ba/flask_login.py#L718-L739 .. _Disconnection Pipeline: pipeline.html#disconnection-pipeline diff --git a/docs/pipeline.rst b/docs/pipeline.rst index 60eaabee..d1699575 100644 --- a/docs/pipeline.rst +++ b/docs/pipeline.rst @@ -272,6 +272,8 @@ such as ``SOCIAL_AUTH_TWITTER_PIPELINE``. Backend-specific pipelines will overri the default and ``SOCIAL_AUTH_PIPELINE`` settings. +.. _disconnection-pipeline: + Disconnection Pipeline ---------------------- diff --git a/docs/storage.rst b/docs/storage.rst index 82077173..e17e01b1 100644 --- a/docs/storage.rst +++ b/docs/storage.rst @@ -101,8 +101,8 @@ an arbitrary row when stored provider data matches multiple associations. raise NotImplementedError('Implement in subclass') @classmethod - def disconnect(cls, name, user, association_id=None): - """Disconnect the social account for the given user""" + def disconnect(cls, entry): + """Remove the given social account association""" raise NotImplementedError('Implement in subclass')