Let’s say I have a model like this:
class Event(models.Model):
PLANNED = 0
OPEN = 1
CLOSED = 2
EVENT_STATES = (
(PLANNED, "Planned"),
(OPEN, "Open"),
(CLOSED, "Closed"),
)
begin_timestamp = models.DateTimeField(null=True, blank=True)
end_timestamp = models.DateTimeField(null=True, blank=True)
state = models.PositiveIntegerField(choices=EVENT_STATES)
# more fields
What I’d like to do is for the state
field to go from PLANNED
to OPEN
when the current timestamp is equal to the value of begin_timestamp
for a given model instance, as well as for it to go from OPEN
to CLOSED
upon reaching end_timestamp
.
This could actually be achieved easily by making state
a property rather than a field, but there’s a catch: the value of state
must be able to be modified manually too, so it can’t just be a computed property.
For example, I might want to close an event before its end timestamp.
I really don’t want to have to restort to using celery or any complicated stuff for this, so here’s what I thought:
class Event(models.Model):
PLANNED = 0
OPEN = 1
CLOSED = 2
EVENT_STATES = (
(PLANNED, "Planned"),
(OPEN, "Open"),
(CLOSED, "Closed"),
)
begin_timestamp = models.DateTimeField(null=True, blank=True)
end_timestamp = models.DateTimeField(null=True, blank=True)
_state = models.PositiveIntegerField(choices=EVENT_STATES)
# more fields
@property
def state(self):
if self._state == Event.PLANNED and self.begin_timestamp >= now:
self._state = Event.OPEN
self.save()
if self._state == Event.OPEN and self.end_timestamp <= now:
self._state = Event.CLOSED
self.save()
return self._state
@state.setter
def state(self, value):
self._state = value
This way, the very first time an Event is accessed in any way after its begin timestamp, its state field will get updated and the correct value will be shown. Same thing for accessing an instance after its end timestamp.
I know that, in general, property getters should not have any side effects, but I can’t seem to find any drawbacks that would come with this approach.
Is this okay to do? Is there a better way without giving up on the simplicity? Thank you all.