introducing historicobjects
This commit is contained in:
parent
c6a97815d7
commit
aaf248a927
3 changed files with 32 additions and 17 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue