Plain is headed towards 1.0! Subscribe for development updates →

 1from __future__ import annotations
 2
 3from datetime import datetime
 4from typing import Any, Self
 5
 6from plain import models
 7from plain.models import types
 8from plain.utils import timezone
 9
10
11class CachedItemQuerySet(models.QuerySet["CachedItem"]):
12    def expired(self) -> Self:
13        return self.filter(expires_at__lt=timezone.now())
14
15    def unexpired(self) -> Self:
16        return self.filter(expires_at__gte=timezone.now())
17
18    def forever(self) -> Self:
19        return self.filter(expires_at=None)
20
21
22@models.register_model
23class CachedItem(models.Model):
24    key: str = types.CharField(max_length=255)
25    value: Any = types.JSONField(required=False, allow_null=True)
26    expires_at: datetime | None = types.DateTimeField(required=False, allow_null=True)
27    created_at: datetime = types.DateTimeField(auto_now_add=True)
28    updated_at: datetime = types.DateTimeField(auto_now=True)
29
30    query: CachedItemQuerySet = CachedItemQuerySet()
31
32    model_options = models.Options(
33        indexes=[
34            models.Index(fields=["expires_at"]),
35        ],
36        constraints=[
37            models.UniqueConstraint(
38                fields=["key"], name="plaincache_cacheditem_unique_key"
39            ),
40        ],
41    )
42
43    def __str__(self) -> str:
44        return self.key