datatracker/ietf/utils/history.py
Ole Laursen 419f387bce Make find_history_active_at return the original object if it is
currently active, otherwise we can't see from the return value whether
a given time predates the history set. The downside is that the caller
may now need to check whether it got a history object or the same
object back.
 - Legacy-Id: 4560
2012-07-02 18:09:42 +00:00

61 lines
2.2 KiB
Python

def find_history_active_at(obj, time):
"""Assumes obj has a corresponding history model (e.g. obj could
be Person with a corresponding PersonHistory model), then either
returns the object itself if it was active at time, or the history
object active at time, or None if time predates the object and its
history (assuming history is complete).
For this to work, the history model must use
related_name="history_set" for the foreign key connecting to the
live model, both models must have a "time" DateTimeField and a
history object must be saved with a copy of the old values and
old time when the time field changes.
"""
if obj.time <= time:
return obj
histories = obj.history_set.order_by('-time')
for h in histories:
if h.time <= time:
return h
return None
def get_history_object_for(obj):
"""Construct history object for obj, i.e. instantiate history
object, copy relevant attributes and set a link to obj, but done
save. Any customizations can be done by the caller afterwards.
Many-to-many fields are not copied.
The history model must use related_name="history_set" for the
foreign key connecting to the live model for this function to be
able to discover it."""
history_model = obj.history_set.model
h = history_model()
# copy attributes shared between history and obj
history_field_names = set(f.name for f in history_model._meta.fields)
for field in obj._meta.fields:
if field is not obj._meta.pk and field.name in history_field_names:
setattr(h, field.name, getattr(obj, field.name))
# try setting foreign key to obj
key_name = obj._meta.object_name.lower()
if key_name in history_field_names:
setattr(h, key_name, obj)
# we can't copy many-to-many fields as h isn't saved yet, leave
# that to caller
return h
def copy_many_to_many_for_history(history_obj, obj):
"""Copy basic many-to-many fields from obj to history_obj."""
# copy many to many
for field in obj._meta.many_to_many:
if field.rel.through and field.rel.through._meta.auto_created:
setattr(history_obj, field.name, getattr(obj, field.name).all())