When there is a need to give a user temporary access in Django, typically, you will need to enable their user and then expire their user manually. This creates an issue as it relies on remembering to disable the user. One way to deal with this is to save the expiration time somewhere and have a script running that will expire users, however this creates another weak point in the app and a critical scheduled job to make sure is always running.
In an app where security was critical and where such a scheduled script would have been subject to audits, I found this method to work perfectly:
Rather than use a boolean to indicate active status, use datetimes for active start and end times and let Django figure out if the user is active based on the current time.
is_active
still behaves as expected using computed properties and a custom setter allows you to totally ignore scheduling when you don't need it by setting user.is_active
as you normally would.
Using this method to control active status, a user can be both granted access in the future (by setting active_from
to a future datetime) and/or have their access revoked in the future (by setting active_until
to a future datetime).
One disadvantage here is that if you are writing custom SQL in your application, the logic for determining if a user is active will need to be duplicated in the database. I solved this by adding a function to the user table (see the included django migration).
At the time of this writing, PostgreSQL does not support a dynamic Generated Column on tables, but this would be the most ideal solution; to replace the expected active
column on the table with a generated one. Perhaps there would be a way to have python get the active status from SQL instead of depending on its own code!