add i18n logic and only store fields that have actually changed
This commit is contained in:
parent
c9d73e9daf
commit
bbce760707
2 changed files with 30 additions and 7 deletions
|
@ -13,6 +13,7 @@ from pydantic.fields import Field
|
||||||
from pydantic.types import Discriminator
|
from pydantic.types import Discriminator
|
||||||
|
|
||||||
from c3nav.api.schema import BaseSchema
|
from c3nav.api.schema import BaseSchema
|
||||||
|
from c3nav.mapdata.fields import I18nField
|
||||||
|
|
||||||
FieldValuesDict: TypeAlias = dict[str, Any]
|
FieldValuesDict: TypeAlias = dict[str, Any]
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ class UpdateObjectOperation(BaseOperation):
|
||||||
instance = list(serializers.deserialize("json", json.dumps([{
|
instance = list(serializers.deserialize("json", json.dumps([{
|
||||||
"model": f"mapdata.{self.obj.model}",
|
"model": f"mapdata.{self.obj.model}",
|
||||||
"pk": self.obj.id,
|
"pk": self.obj.id,
|
||||||
"fields": self.fields,
|
"fields": values,
|
||||||
}])))[0]
|
}])))[0]
|
||||||
instance.save(save_m2m=False)
|
instance.save(save_m2m=False)
|
||||||
return instance.object
|
return instance.object
|
||||||
|
@ -156,7 +157,14 @@ class CollectedChanges(BaseSchema):
|
||||||
changed_object.created = True
|
changed_object.created = True
|
||||||
changed_object.fields.update(operation.fields)
|
changed_object.fields.update(operation.fields)
|
||||||
elif isinstance(operation, UpdateObjectOperation):
|
elif isinstance(operation, UpdateObjectOperation):
|
||||||
changed_object.fields.update(operation.fields)
|
model = apps.get_model('mapdata', operation.obj.model)
|
||||||
|
for field_name, value in operation.fields.items():
|
||||||
|
field = model._meta.get_field(field_name)
|
||||||
|
if isinstance(field, I18nField) and field_name in changed_object.fields:
|
||||||
|
changed_object.fields[field_name] = {lang: val
|
||||||
|
for lang, val in field[field_name].update(value).items()}
|
||||||
|
else:
|
||||||
|
changed_object.fields[field_name] = value
|
||||||
elif isinstance(operation, DeleteObjectOperation):
|
elif isinstance(operation, DeleteObjectOperation):
|
||||||
changed_object.deleted = False
|
changed_object.deleted = False
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.db.models.fields.related import ManyToManyField
|
||||||
|
|
||||||
from c3nav.editor.operations import DatabaseOperation, ObjectReference, FieldValuesDict, CreateObjectOperation, \
|
from c3nav.editor.operations import DatabaseOperation, ObjectReference, FieldValuesDict, CreateObjectOperation, \
|
||||||
UpdateObjectOperation, DeleteObjectOperation, ClearManyToManyOperation, UpdateManyToManyOperation, CollectedChanges
|
UpdateObjectOperation, DeleteObjectOperation, ClearManyToManyOperation, UpdateManyToManyOperation, CollectedChanges
|
||||||
|
from c3nav.mapdata.fields import I18nField
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from asgiref.local import Local as LocalContext
|
from asgiref.local import Local as LocalContext
|
||||||
|
@ -57,7 +58,7 @@ class DatabaseOverlayManager:
|
||||||
def get_model_field_values(instance: Model) -> FieldValuesDict:
|
def get_model_field_values(instance: Model) -> FieldValuesDict:
|
||||||
return json.loads(serializers.serialize("json", [instance]))[0]["fields"]
|
return json.loads(serializers.serialize("json", [instance]))[0]["fields"]
|
||||||
|
|
||||||
def get_ref_and_pre_change_values(self, instance: Model) -> ObjectReference:
|
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, None)
|
||||||
|
@ -65,7 +66,7 @@ class DatabaseOverlayManager:
|
||||||
self.changes.prev_values.setdefault(ref.model, {})[ref.id] = pre_change_values
|
self.changes.prev_values.setdefault(ref.model, {})[ref.id] = pre_change_values
|
||||||
self.changes.prev_reprs.setdefault(ref.model, {})[ref.id] = str(instance)
|
self.changes.prev_reprs.setdefault(ref.model, {})[ref.id] = str(instance)
|
||||||
|
|
||||||
return ref
|
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:
|
||||||
|
@ -79,7 +80,7 @@ class DatabaseOverlayManager:
|
||||||
def handle_post_save(self, instance: Model, created: bool, update_fields: set | None, **kwargs):
|
def handle_post_save(self, instance: Model, created: bool, update_fields: set | None, **kwargs):
|
||||||
field_values = self.get_model_field_values(instance)
|
field_values = self.get_model_field_values(instance)
|
||||||
|
|
||||||
ref = self.get_ref_and_pre_change_values(instance)
|
ref, pre_change_values = self.get_ref_and_pre_change_values(instance)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
self.new_operations.append(CreateObjectOperation(obj=ref, fields=field_values))
|
self.new_operations.append(CreateObjectOperation(obj=ref, fields=field_values))
|
||||||
|
@ -88,10 +89,24 @@ class DatabaseOverlayManager:
|
||||||
if update_fields:
|
if update_fields:
|
||||||
field_values = {name: value for name, value in field_values.items() if name in update_fields}
|
field_values = {name: value for name, value in field_values.items() if name in update_fields}
|
||||||
|
|
||||||
|
field_values = {name: value for name, value in field_values.items() if value != pre_change_values[name]}
|
||||||
|
|
||||||
|
# special diffing within the i18n fields
|
||||||
|
for field_name in tuple(field_values):
|
||||||
|
if isinstance(instance._meta.get_field(field_name), I18nField):
|
||||||
|
before_val = pre_change_values[field_name]
|
||||||
|
after_val = field_values[field_name]
|
||||||
|
|
||||||
|
diff_val = {}
|
||||||
|
for lang in (set(before_val) | set(after_val)):
|
||||||
|
if before_val.get(lang, None) != after_val.get(lang, None):
|
||||||
|
diff_val[lang] = after_val.get(lang, None)
|
||||||
|
field_values[field_name] = diff_val
|
||||||
|
|
||||||
self.new_operations.append(UpdateObjectOperation(obj=ref, fields=field_values))
|
self.new_operations.append(UpdateObjectOperation(obj=ref, fields=field_values))
|
||||||
|
|
||||||
def handle_post_delete(self, instance: Model, **kwargs):
|
def handle_post_delete(self, instance: Model, **kwargs):
|
||||||
ref = self.get_ref_and_pre_change_values(instance)
|
ref, pre_change_values = self.get_ref_and_pre_change_values(instance)
|
||||||
self.new_operations.append(DeleteObjectOperation(obj=ref))
|
self.new_operations.append(DeleteObjectOperation(obj=ref))
|
||||||
|
|
||||||
def handle_m2m_changed(self, sender: Type[Model], instance: Model, action: str, model: Type[Model],
|
def handle_m2m_changed(self, sender: Type[Model], instance: Model, action: str, model: Type[Model],
|
||||||
|
@ -108,7 +123,7 @@ class DatabaseOverlayManager:
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
ref = self.get_ref_and_pre_change_values(instance)
|
ref, pre_change_values = self.get_ref_and_pre_change_values(instance)
|
||||||
|
|
||||||
if action == "post_clear":
|
if action == "post_clear":
|
||||||
self.new_operations.append(ClearManyToManyOperation(obj=ref, field=field.name))
|
self.new_operations.append(ClearManyToManyOperation(obj=ref, field=field.name))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue