From 17abd90c46fe646797054dbb85fd79ec6bb039c1 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 31 Oct 2023 10:47:31 -0700 Subject: [PATCH] Maybe hack-y but working custom field serialization --- ...omfieldboolean_customfielddate_and_more.py | 19 +++++----- src/documents/models.py | 25 ++++++++----- src/documents/serialisers.py | 35 ++++++++++++------- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/documents/migrations/1040_customfield_customfieldboolean_customfielddate_and_more.py b/src/documents/migrations/1040_customfield_customfieldboolean_customfielddate_and_more.py index 39d4a019e..2719f7878 100644 --- a/src/documents/migrations/1040_customfield_customfieldboolean_customfielddate_and_more.py +++ b/src/documents/migrations/1040_customfield_customfieldboolean_customfielddate_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.5 on 2023-10-28 02:54 +# Generated by Django 4.2.5 on 2023-10-31 17:28 import django.db.models.deletion import django.utils.timezone @@ -92,16 +92,6 @@ class Migration(migrations.Migration): to="documents.customfield", ), ), - ( - "owner", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - verbose_name="owner", - ), - ), ], options={ "verbose_name": "custom field instance", @@ -229,4 +219,11 @@ class Migration(migrations.Migration): ), ], ), + migrations.AddConstraint( + model_name="customfieldinstance", + constraint=models.UniqueConstraint( + fields=("document", "field"), + name="documents_customfieldinstance_unique_document_field", + ), + ), ] diff --git a/src/documents/models.py b/src/documents/models.py index ae42a09d7..8483ed6e3 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -4,6 +4,7 @@ import os import re from collections import OrderedDict from pathlib import Path +from typing import Any from typing import Final from typing import Optional @@ -920,7 +921,7 @@ class CustomField(models.Model): return f"{self.name} : {self.data_type}" -class CustomFieldInstance(ModelWithOwner): +class CustomFieldInstance(models.Model): """ A single instance of a field, attached to a CustomField for the name and type and attached to a single Document to be metadata for it @@ -952,6 +953,12 @@ class CustomFieldInstance(ModelWithOwner): ordering = ("created",) verbose_name = _("custom field instance") verbose_name_plural = _("custom field instances") + constraints = [ + models.UniqueConstraint( + fields=["document", "field"], + name="%(app_label)s_%(class)s_unique_document_field", + ), + ] def __str__(self) -> str: return str(self.field) + f" : {self.value}" @@ -1002,17 +1009,19 @@ class CustomFieldInstance(ModelWithOwner): @staticmethod def from_json( document: Document, - field: CustomField, - data, + field: OrderedDict, + value: Any, ) -> "CustomFieldInstance": - instance = CustomFieldInstance.objects.create( + instance, _ = CustomFieldInstance.objects.get_or_create( document=document, - field=field, - data_type=data["type"], + field=CustomField.objects.get(id=field["id"]), + ) + instance.field_type.objects.update_or_create( + parent=instance, + defaults={"value": value}, ) - instance.field_type.objects.create(value=data["value"], parent=instance) - return field + return instance class CustomFieldShortText(models.Model): diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index 3bfb4b3c4..35e6b7de4 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -2,6 +2,7 @@ import datetime import math import re import zoneinfo +from typing import Any import magic from celery import states @@ -406,26 +407,16 @@ class CustomFieldSerializer(serializers.ModelSerializer): ] -class CustomFieldInstanceSerializer(serializers.ModelSerializer): - parent = CustomFieldSerializer() +class CustomFieldInstanceSerializer(serializers.Serializer): + field = CustomFieldSerializer(required=True) value = SerializerMethodField() def get_value(self, obj: CustomFieldInstance): return obj.value - def create(self, validated_data): - parent_data = validated_data.pop("parent") - parent = CustomField.objects.get(id=parent_data["id"]) - instance = CustomFieldInstance.objects.create(parent=parent) - return instance - - def update(self, instance: CustomFieldInstance): - return instance - class Meta: - model = CustomFieldInstance fields = [ - "parent", + "field", "value", ] @@ -463,7 +454,25 @@ class DocumentSerializer(OwnedObjectSerializer, DynamicFieldsModelSerializer): doc["content"] = doc.get("content")[0:550] return doc + def to_internal_value(self, data: Any) -> Any: + # hack-y + values = super().to_internal_value(data) + if "custom_fields" in values: + for index, field_instance in enumerate(values["custom_fields"]): + data_custom_field = data["custom_fields"][index] + field_instance["field"]["id"] = data_custom_field["field"]["id"] + field_instance["value"] = data_custom_field["value"] + return values + def update(self, instance, validated_data): + if "custom_fields" in validated_data: + custom_fields = validated_data.pop("custom_fields") + for field_data in custom_fields: + CustomFieldInstance.from_json( + document=instance, + field=field_data["field"], + value=field_data["value"], + ) if "created_date" in validated_data and "created" not in validated_data: new_datetime = datetime.datetime.combine( validated_data.get("created_date"),