-
Notifications
You must be signed in to change notification settings - Fork 772
migration for inactive user purge #6676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
migration for inactive user purge #6676
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r+wc
@smithellis Forgot to mention one more thing. Just FYI, you can use |
|
||
cutoff_date = timezone.now() - timedelta(days=3*365) | ||
|
||
query = User.objects.filter(last_login__lt=cutoff_date).annotate(has_content=has_content_criteria) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you using annotate
here instead of filter/exclude/Exists
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use case absolutely works - I think it's just not specifically called out in the 4.2 docs but is in later docs. I can run this query and see the output and it builds valid sql which executes properly.
I'm annotating here so we can later divide our users into those with and those without content, so we can execute a quicker delete process on non-content users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed this to two separate queries.
""" | ||
Delete users who haven't logged in for over three years. | ||
""" | ||
User = get_user_model() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be User = apps.get_model("auth", "User")
in migrations similar to the previous one (0034)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is necessary because the delete_user_pipeline
function needs an actual User instance vs. a historical model.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we cannot use the apps.get_model()
here, probably we should refactor and change our approach. The migration needs to work the the model state and the time of its creation. If in the future the user model changes, the migration will most probably fail.
I would suggest to either refactor the migration in order to use methods compatible with the historical model (eg avoid properties and custom managers) or consider a different approach altogether.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this looks good but we should use the historical user model here.
""" | ||
Delete users who haven't logged in for over three years. | ||
""" | ||
User = get_user_model() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we cannot use the apps.get_model()
here, probably we should refactor and change our approach. The migration needs to work the the model state and the time of its creation. If in the future the user model changes, the migration will most probably fail.
I would suggest to either refactor the migration in order to use methods compatible with the historical model (eg avoid properties and custom managers) or consider a different approach altogether.
1 - get all users who we consider inactive (3 years since login)
2 - divide into users having content and users without content
3 - hard deletes non-content users using the
_base_manager
4 - pushes other users through the deletion pipeline
5 - implements batching to manage resources