introducing historicobjects

This commit is contained in:
Laura Klünder 2024-09-12 21:43:31 +02:00
parent c6a97815d7
commit aaf248a927
3 changed files with 32 additions and 17 deletions

View file

@ -30,6 +30,27 @@ class ObjectReference(BaseSchema):
return cls(model=instance._meta.model_name, id=instance.pk) return cls(model=instance._meta.model_name, id=instance.pk)
class PreviousObject(BaseSchema):
titles: dict[str, str] | None
values: FieldValuesDict
class PreviousObjects(BaseSchema):
objects: dict[str, dict[int, PreviousObject]] = {}
def get(self, ref: ObjectReference) -> PreviousObject | None:
return self.objects.get(ref.model, {}).get(ref.id, None)
def set(self, ref: ObjectReference, values: FieldValuesDict, titles: dict | None):
self.objects.setdefault(ref.model, {})[ref.id] = PreviousObject(
values=values,
titles=titles,
)
def get_ids(self) -> dict[str, set[int]]:
return {model: set(objs.keys()) for model, objs in self.objects.items()}
class BaseOperation(BaseSchema): class BaseOperation(BaseSchema):
obj: ObjectReference obj: ObjectReference
uuid: UUID = Field(default_factory=uuid4) uuid: UUID = Field(default_factory=uuid4)
@ -168,13 +189,11 @@ class ChangedObject(BaseSchema):
class CollectedChanges(BaseSchema): class CollectedChanges(BaseSchema):
uuid: UUID = Field(default_factory=uuid4) uuid: UUID = Field(default_factory=uuid4)
prev_titles: dict[str, dict[int, dict[str, str] | None]] = {} prev: PreviousObjects = PreviousObjects()
prev_values: dict[str, dict[int, FieldValuesDict]] = {}
operations: list[DatabaseOperation] = [] operations: list[DatabaseOperation] = []
def prefetch(self) -> "CollectedChangesPrefetch": def prefetch(self) -> "CollectedChangesPrefetch":
ids_to_query: dict[str, set[int]] = {model_name: set(val.keys()) ids_to_query: dict[str, set[int]] = self.prev.get_ids()
for model_name, val in self.prev_values.items()}
instances: dict[ObjectReference, Model] = {} instances: dict[ObjectReference, Model] = {}
for model_name, ids in ids_to_query.items(): for model_name, ids in ids_to_query.items():
@ -236,19 +255,18 @@ class CollectedChangesPrefetch:
def apply(self): def apply(self):
# todo: what if unique constraint error occurs? # todo: what if unique constraint error occurs?
prev_values = copy.deepcopy(self.changes.prev_values)
for operation in self.changes.operations: for operation in self.changes.operations:
if isinstance(operation, CreateObjectOperation): if isinstance(operation, CreateObjectOperation):
self.instances[operation.obj] = operation.apply_create() self.instances[operation.obj] = operation.apply_create()
else: else:
in_prev_values = operation.obj.id in prev_values.get(operation.obj.model, {}) prev_obj = self.changes.prev.get(operation.obj)
if not in_prev_values: if prev_obj is None:
print('WARN WARN WARN') print('WARN WARN WARN')
values = prev_values.setdefault(operation.obj.model, {}).setdefault(operation.obj.id, {}) values = prev_obj.values
try: try:
instance = self.instances[operation.obj] instance = self.instances[operation.obj]
except KeyError: except KeyError:
if not in_prev_values: if prev_obj is None:
instance = apps.get_model("mapdata", operation.obj.model).filter(pk=operation.obj.id).first() instance = apps.get_model("mapdata", operation.obj.model).filter(pk=operation.obj.id).first()
else: else:
instance = None instance = None

View file

@ -65,18 +65,15 @@ class DatabaseOverlayManager:
def get_ref_and_pre_change_values(self, instance: Model) -> tuple[ObjectReference, FieldValuesDict]: def get_ref_and_pre_change_values(self, instance: Model) -> tuple[ObjectReference, FieldValuesDict]:
ref = ObjectReference.from_instance(instance) ref = ObjectReference.from_instance(instance)
pre_change_values = self.pre_change_values.pop(ref, None) pre_change_values = self.pre_change_values.pop(ref)
if pre_change_values: self.changes.prev.set(ref, values=pre_change_values, titles=getattr(instance, 'titles', None))
self.changes.prev_values.setdefault(ref.model, {})[ref.id] = pre_change_values
self.changes.prev_titles.setdefault(ref.model, {})[ref.id] = getattr(instance, 'titles', None)
return ref, pre_change_values return ref, pre_change_values
def handle_pre_change_instance(self, instance: Model, **kwargs): def handle_pre_change_instance(self, instance: Model, **kwargs):
if instance.pk is None: if instance.pk is None:
return return
ref = ObjectReference.from_instance(instance) ref = ObjectReference.from_instance(instance)
if ref not in self.pre_change_values and ref.id not in self.changes.prev_values.get(ref.model, {}): if ref not in self.pre_change_values and self.changes.prev.get(ref) is None:
self.pre_change_values[ref] = self.get_model_field_values( self.pre_change_values[ref] = self.get_model_field_values(
instance._meta.model.objects.get(pk=instance.pk) instance._meta.model.objects.get(pk=instance.pk)
) )

View file

@ -198,7 +198,7 @@ def changeset_detail(request, pk):
if changed_object.created and not changed_object.deleted: if changed_object.created and not changed_object.deleted:
added_redirects.setdefault(changed_object.fields["target"], set()).add(changed_object.fields["slug"]) added_redirects.setdefault(changed_object.fields["target"], set()).add(changed_object.fields["slug"])
elif changed_object.deleted: elif changed_object.deleted:
orig_values = changeset.changes.prev_values["locationredirect"][changed_object.obj.id] orig_values = changeset.changes.prev.get(changed_object.obj).values
removed_redirects.setdefault(orig_values["target"], set()).add(orig_values["slug"]) removed_redirects.setdefault(orig_values["target"], set()).add(orig_values["slug"])
else: else:
raise ValueError # dafuq? not possibile through the editor raise ValueError # dafuq? not possibile through the editor
@ -218,7 +218,7 @@ def changeset_detail(request, pk):
else: else:
title = next(iter(changed_object.titles.values())) title = next(iter(changed_object.titles.values()))
prev_values = changeset.changes.prev_values[changed_object.obj.model][changed_object.obj.id] prev_values = changeset.changes.prev.get(changed_object.obj).values
edit_url = None edit_url = None
if not changed_object.deleted: if not changed_object.deleted: