bookwyrm/bookwyrm/models/readthrough.py
Bart Schuurmans 0d621b68e0 Reorder operations in save() overrides
Accessing many-to-many relations before saving is no longer allowed.

Reorder all operations consistently:
1. Validations
2. Modify own fields
3. Perform save by calling super().save()
4. Modify related objects and clear caches

Especially clearing caches should be done after actually saving, otherwise the old data can be
re-added immediately by another request before the new data is written.
2024-04-25 10:12:30 +02:00

77 lines
2.5 KiB
Python

""" progress in a book """
from django.core import validators
from django.core.cache import cache
from django.db import models
from django.db.models import F, Q
from .base_model import BookWyrmModel
class ProgressMode(models.TextChoices):
"""types of progress available"""
PAGE = "PG", "page"
PERCENT = "PCT", "percent"
class ReadThrough(BookWyrmModel):
"""Store a read through a book in the database."""
user = models.ForeignKey("User", on_delete=models.PROTECT)
book = models.ForeignKey("Edition", on_delete=models.PROTECT)
progress = models.IntegerField(
validators=[validators.MinValueValidator(0)], null=True, blank=True
)
progress_mode = models.CharField(
max_length=3, choices=ProgressMode.choices, default=ProgressMode.PAGE
)
start_date = models.DateTimeField(blank=True, null=True)
finish_date = models.DateTimeField(blank=True, null=True)
stopped_date = models.DateTimeField(blank=True, null=True)
is_active = models.BooleanField(default=True)
def save(self, *args, **kwargs):
"""update user active time"""
# an active readthrough must have an unset finish date
if self.finish_date or self.stopped_date:
self.is_active = False
super().save(*args, **kwargs)
cache.delete(f"latest_read_through-{self.user_id}-{self.book_id}")
self.user.update_active_date()
def create_update(self):
"""add update to the readthrough"""
if self.progress:
return self.progressupdate_set.create(
user=self.user, progress=self.progress, mode=self.progress_mode
)
return None
class Meta:
"""Don't let readthroughs end before they start"""
constraints = [
models.CheckConstraint(
check=Q(finish_date__gte=F("start_date")), name="chronology"
)
]
ordering = ("-start_date",)
class ProgressUpdate(BookWyrmModel):
"""Store progress through a book in the database."""
user = models.ForeignKey("User", on_delete=models.PROTECT)
readthrough = models.ForeignKey("ReadThrough", on_delete=models.CASCADE)
progress = models.IntegerField(validators=[validators.MinValueValidator(0)])
mode = models.CharField(
max_length=3, choices=ProgressMode.choices, default=ProgressMode.PAGE
)
def save(self, *args, **kwargs):
"""update user active time"""
self.user.update_active_date()
super().save(*args, **kwargs)