we will reuse IDs, instead of having temporary ones

This commit is contained in:
Laura Klünder 2024-08-24 13:20:39 +02:00
parent 71789e7f41
commit 77ce6fef2e

View file

@ -21,16 +21,15 @@ except ImportError:
FieldValuesDict: TypeAlias = dict[str, Any]
ExistingOrCreatedID: TypeAlias = int # negative = temporary ID of created object
class ObjectReference(BaseSchema):
model_config = ConfigDict(frozen=True)
model: str
id: ExistingOrCreatedID
id: int
@classmethod
def simple_from_instance(cls, instance: Model):
def from_instance(cls, instance: Model):
"""
This method will not convert the ID yet!
"""
@ -121,39 +120,13 @@ class ChangesetOverlayManager:
new_changes: bool = False
pre_change_values: dict[ObjectReference, FieldValuesDict] = field(default_factory=dict)
# maps negative IDs of created objects to the ID during the current transaction
mapped_ids: dict[ObjectReference, int] = field(default_factory=dict)
# maps IDs as used during the current transaction to the negative IDs
reverse_mapped_ids: dict[ObjectReference, int] = field(default_factory=dict)
def ref_lookup(self, ref: ObjectReference):
local_value = self.mapped_ids.get(ref, None)
return ref if local_value is None else ObjectReference(model=ref.model, id=local_value)
def reverse_ref_lookup(self, ref: ObjectReference):
created_value = self.reverse_mapped_ids.get(ref, None)
return ref if created_value is None else ObjectReference(model=ref.model, id=created_value)
def get_model_field_values(self, instance: Model) -> FieldValuesDict:
values = json.loads(serializers.serialize("json", [instance]))[0]["fields"]
for field in instance._meta.get_fields():
if field.name not in values:
continue
if isinstance(field, (OneToOneField, ForeignKey)):
value = values[field.name]
if value is not None:
values[field.name] = self.reverse_ref_lookup(
ObjectReference(model=field.model._meta.model_name, id=value)
).id
return values
return json.loads(serializers.serialize("json", [instance]))[0]["fields"]
def handle_pre_change_instance(self, sender: Type[Model], instance: Model, **kwargs):
if instance.pk is None:
return
ref = ObjectReference.simple_from_instance(instance)
if ref in self.reverse_mapped_ids:
return
ref = ObjectReference.from_instance(instance)
if ref not in self.pre_change_values and ref not in self.changes.prev_values:
self.pre_change_values[ref] = self.get_model_field_values(
instance._meta.model.objects.get(pk=instance.pk)
@ -163,16 +136,10 @@ class ChangesetOverlayManager:
update_fields: set | None, **kwargs):
field_values = self.get_model_field_values(instance)
ref = ObjectReference.from_instance(instance)
if created:
created_id = min([change.obj.id for change in self.changes
if isinstance(change, CreateObjectChange)], default=0)-1
model_name = instance._meta.model_name
self.mapped_ids[ObjectReference(model=model_name, id=created_id)] = instance.pk
self.reverse_mapped_ids[ObjectReference(model=model_name, id=instance.pk)] = created_id
self.changes.changes.append(CreateObjectChange(
obj=ObjectReference(model=instance._meta.model_name, id=created_id),
fields=field_values
))
self.changes.changes.append(CreateObjectChange(obj=ref, fields=field_values))
from pprint import pprint
pprint(self.changes)
return
@ -180,20 +147,16 @@ class ChangesetOverlayManager:
if update_fields:
field_values = {name: value for name, value in field_values.items() if name in update_fields}
ref = self.reverse_ref_lookup(ObjectReference.simple_from_instance(instance))
pre_change_values = self.pre_change_values.pop(ref, None)
if pre_change_values:
self.changes.prev_values[ref] = pre_change_values
self.changes.prev_reprs[ref] = str(instance)
self.changes.changes.append(UpdateObjectChange(
obj=ref,
fields=field_values
))
self.changes.changes.append(UpdateObjectChange(obj=ref, fields=field_values))
from pprint import pprint
pprint(self.changes)
def handle_post_delete(self, sender: Type[Model], instance: Model, **kwargs):
ref = self.reverse_ref_lookup(ObjectReference.simple_from_instance(instance))
ref = ObjectReference.from_instance(instance)
pre_change_values = self.pre_change_values.pop(ref, None)
if pre_change_values:
self.changes.prev_values[ref] = pre_change_values