python 41 lines · 7 steps

A batched session-cleanup command in Django

A custom management command deletes expired session rows in safe, bounded batches with a configurable grace period.

Explained by highlit
1from datetime import timedelta
2 
3from django.contrib.sessions.models import Session
4from django.core.management.base import BaseCommand
5from django.utils import timezone
6 
7 
8class Command(BaseCommand):
9 help = "Delete session records that have already expired."
10 
11 def add_arguments(self, parser):
12 parser.add_argument(
13 "--grace-hours",
14 type=int,
15 default=0,
16 help="Keep sessions that expired within the last N hours.",
17 )
18 parser.add_argument(
19 "--batch-size",
20 type=int,
21 default=5000,
22 help="Number of rows to delete per query.",
23 )
24 
25 def handle(self, *args, **options):
26 cutoff = timezone.now() - timedelta(hours=options["grace_hours"])
27 batch_size = options["batch_size"]
28 expired = Session.objects.filter(expire_date__lt=cutoff)
29 
30 total = 0
31 while True:
32 pks = list(expired.values_list("pk", flat=True)[:batch_size])
33 if not pks:
34 break
35 deleted, _ = Session.objects.filter(pk__in=pks).delete()
36 total += deleted
37 self.stdout.write(f"Purged {deleted} expired sessions...")
38 
39 self.stdout.write(
40 self.style.SUCCESS(f"Done. Removed {total} expired sessions.")
41 )
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Deleting in bounded batches keeps a single cleanup query from locking or overwhelming the database.
  2. 2Exposing tunables like grace period and batch size as command arguments makes an operational task safe to run in different environments.
  3. 3Collecting primary keys first and then deleting by pk__in avoids surprises from a moving filter during iteration.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A batched session-cleanup command in Django — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code