diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2025-01-30 13:08:34 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2025-02-19 14:45:56 +0100 |
commit | 042b8f956369c115536dfe7e33d9c0461dafe539 (patch) | |
tree | 90f8577c5e52047be00f5aeb2f31d010f0d65fb2 | |
parent | bfae6a086ff5d35c794a5c5c0380bf2332661452 (diff) | |
download | Ishtar-042b8f956369c115536dfe7e33d9c0461dafe539.tar.bz2 Ishtar-042b8f956369c115536dfe7e33d9c0461dafe539.zip |
✨ admin: better management of Import - Item keys, import/export, links all user/imports
-rw-r--r-- | archaeological_operations/tests.py | 4 | ||||
-rw-r--r-- | ishtar_common/admin.py | 64 | ||||
-rw-r--r-- | ishtar_common/data_importer.py | 8 | ||||
-rw-r--r-- | ishtar_common/forms_common.py | 16 | ||||
-rw-r--r-- | ishtar_common/migrations/0260_itemkey_importer_type.py | 62 | ||||
-rw-r--r-- | ishtar_common/models_common.py | 33 | ||||
-rw-r--r-- | ishtar_common/models_imports.py | 138 | ||||
-rw-r--r-- | ishtar_common/serializers.py | 19 | ||||
-rw-r--r-- | ishtar_common/serializers_utils.py | 97 |
9 files changed, 336 insertions, 105 deletions
diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index 18e17cca5..26217d7c3 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -202,7 +202,7 @@ class ImportTest(BaseImportTest): def init_ope_targetkey(self, imp): # doing manually connections - q = Q(importer=imp) | Q(user=imp.user) + q = Q(ishtar_import=imp) | Q(user=imp.user) | Q(importer_type=imp.importer_type) if imp.associated_group: q |= Q(group=imp.associated_group) for ik in ItemKey.objects.filter(q).all(): @@ -565,7 +565,7 @@ class ImportOperationTest(ImportTest, TestCase): other_imp = form.save(self.ishtar_user) # re-associate with another import - q = Q(importer=impt) | Q(user=impt.user) + q = Q(ishtar_import=impt) | Q(user=impt.user) | Q(importer_type=impt.importer_type) if impt.associated_group: q |= Q(group=impt.associated_group) for ik in ItemKey.objects.filter(q).all(): diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 7b1aa48d4..a2dfc63aa 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -281,23 +281,25 @@ def serialize_action(dir_name, model_list): else: modellist = [modeladmin.model] opts = modeladmin.model._meta + if getattr(modeladmin, "serialize_filter_queryset", None): + queryset = queryset.filter(**modeladmin.serialize_filter_queryset) result = generic_get_results( modellist, dir_name, result_queryset={opts.object_name: queryset} ) basename = str(opts).replace(".", "_") in_memory = BytesIO() - zip = zipfile.ZipFile(in_memory, "a") + current_zip = zipfile.ZipFile(in_memory, "a") for key in result.keys(): __, model_name = key - zip.writestr(dir_name + os.sep + model_name + ".json", result[key]) + current_zip.writestr(dir_name + os.sep + model_name + ".json", result[key]) # info - zip.writestr("info.json", json.dumps(serialization_info(), indent=2)) + current_zip.writestr("info.json", json.dumps(serialization_info(), indent=2)) # fix for Linux zip files read in Windows - for file in zip.filelist: - file.create_system = 0 - zip.close() + for cfile in current_zip.filelist: + cfile.create_system = 0 + current_zip.close() response = HttpResponse(content_type="application/zip") response["Content-Disposition"] = "attachment; filename={}.zip".format(basename) in_memory.seek(0) @@ -2124,15 +2126,11 @@ class ImporterGroupImporterInline(admin.TabularInline): extra = 3 -serialize_importer_group_action = serialize_action("common_imports", IMPORT_MODEL_LIST) -serialize_importer_group_action.short_description = SERIALIZE_DESC - - @admin.register(models.ImporterGroup, site=admin_site) class ImporterGroupAdmin(ImportJSONActionAdmin): list_display = ("name", "importer_types_label", "available") actions = [ - serialize_importer_group_action, + serialize_importer_action, change_value("available", True, _("Make available")), change_value("available", False, _("Make unavailable")), ] @@ -2359,6 +2357,7 @@ class ImportAdmin(admin.ModelAdmin): "creation_date", ) autocomplete_fields = ["user"] + search_fields = ("name", "importer_type__name") admin_site.register(models.Import, ImportAdmin) @@ -2377,23 +2376,6 @@ class ImportGroupAdmin(admin.ModelAdmin): autocomplete_fields = ["user"] -class TargetKeyGroupAdmin(admin.ModelAdmin): - list_display = ("name", "all_user_can_use", "all_user_can_modify", "available") - search_fields = ("name",) - - -admin_site.register(models.TargetKeyGroup, TargetKeyGroupAdmin) - - -class TargetKeyAdmin(admin.ModelAdmin): - list_display = ("target", "importer_type", "column_nb", "key", "value", "is_set") - list_filter = ("is_set", "target__column__importer_type") - search_fields = ("target__target", "value", "key") - - -admin_site.register(models.TargetKey, TargetKeyAdmin) - - class OperationTypeAdmin(GeneralTypeAdmin): extra_list_display = ["order", "preventive"] model = models.OperationType @@ -2410,12 +2392,30 @@ class SpatialReferenceSystemAdmin(GeneralTypeAdmin): admin_site.register(models.SpatialReferenceSystem, SpatialReferenceSystemAdmin) -class ItemKeyAdmin(admin.ModelAdmin): - list_display = ("content_type", "key", "content_object", "importer") - search_fields = ("key",) +@admin.register(models.ItemKey, site=admin_site) +class ItemKeyAdmin(ImportJSONActionAdmin): + list_display = ( + "content_type", "content_type_model", "key", "content_object", "linked_to_all", + "linked_to_importer_type", "linked_to_importer", "linked_to_user" + ) + search_fields = ("key", "content_type__model") + list_filter = (("content_type", admin.RelatedOnlyFieldListFilter),) + autocomplete_fields = ["user", "ishtar_import"] + actions = [ + serialize_type_action + ] + serialize_filter_queryset = { + "user__isnull": True, + "group__isnull": True, + "ishtar_import__isnull": True + } -admin_site.register(models.ItemKey, ItemKeyAdmin) +@admin.register(models.TargetKey, site=admin_site) +class TargetKeyAdmin(admin.ModelAdmin): + list_display = ("target", "importer_type", "column_nb", "key", "value", "is_set") + list_filter = ("is_set", "target__column__importer_type") + search_fields = ("target__target", "value", "key") @admin.register(models.ImportColumnValue, site=admin_site) diff --git a/ishtar_common/data_importer.py b/ishtar_common/data_importer.py index defea4da8..0c58e04f7 100644 --- a/ishtar_common/data_importer.py +++ b/ishtar_common/data_importer.py @@ -536,7 +536,7 @@ class StrChoiceFormater(Formater, ChoiceChecker): def new(self, value): return - def add_key(self, obj, value, importer=None): + def add_key(self, obj, value, ishtar_import=None): return def format(self, value): @@ -575,14 +575,14 @@ class TypeFormater(StrChoiceFormater): if self.import_instance: for item in model.objects.all(): self.choices.append((item.pk, str(item))) - for key in item.get_keys(importer=import_instance): + for key in item.get_keys(current_import=import_instance): self.equiv_dict[key] = item def prepare(self, value): return slugify(str(value).strip()) - def add_key(self, obj, value, importer=None): - obj.add_key(slugify(value), force=True, importer=importer) + def add_key(self, obj, value, ishtar_import=None): + obj.add_key(slugify(value), force=True, ishtar_import=ishtar_import) def new(self, value): values = copy.copy(self.defaults) diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 3fa819a8f..187941bb6 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -605,6 +605,7 @@ class TargetKeyForm(forms.ModelForm): ] if self.user.is_superuser: choices += [("all", _("all users"))] + choices += [("all-importers", _("all users and importers"))] self.fields["remember"].choices = choices self.fields["remember"].widget.attrs["class"] = "auto" self.remember_choices = choices @@ -625,7 +626,7 @@ class TargetKeyForm(forms.ModelForm): def save(self, commit=True): try: - super(TargetKeyForm, self).save(commit) + super().save(commit) except ImporterError: return if not self.cleaned_data.get("value") or not self.user: @@ -644,23 +645,28 @@ class TargetKeyForm(forms.ModelForm): ) remember = self.cleaned_data.get("remember") + self.instance.associated_import = self.associated_import + force_importer_type, force_all = False, False if remember == "import" and self.associated_import: - self.instance.associated_import = self.associated_import self.instance.associated_user = None self.instance.associated_group = None elif remember == "group" and can_edit_group: - self.instance.associated_import = None self.instance.associated_user = None self.instance.associated_group = self.associated_import.associated_group elif remember == "all" and self.user.is_superuser: - self.instance.associated_import = None self.instance.associated_user = None self.instance.associated_group = None + force_importer_type = True + elif remember == "all-importers" and self.user.is_superuser: + self.instance.associated_user = None + self.instance.associated_group = None + force_all = True else: # for me! - self.instance.associated_import = None self.instance.associated_user = self.user.ishtaruser self.instance.associated_group = None + self.instance.create_itemkey(force_importer_type=force_importer_type, + force_all=force_all) self.instance.save() diff --git a/ishtar_common/migrations/0260_itemkey_importer_type.py b/ishtar_common/migrations/0260_itemkey_importer_type.py new file mode 100644 index 000000000..789f22162 --- /dev/null +++ b/ishtar_common/migrations/0260_itemkey_importer_type.py @@ -0,0 +1,62 @@ +# Generated by Django 2.2.24 on 2025-01-30 15:55 + +from django.db import migrations, models, connection +import django.db.models.deletion + + +def migrate_import_type(apps, __): + ItemKey = apps.get_model("ishtar_common", "ItemKey") + Import = apps.get_model("ishtar_common", "Import") + + with connection.cursor() as cursor: + cursor.execute("SELECT id, importer_id FROM ishtar_common_itemkey WHERE importer_id IS NOT NULL;") + for ik_id, import_id in cursor.fetchall(): + importer_type_id = Import.objects.get(pk=import_id).importer_type_id + ik = ItemKey.objects.get(pk=ik_id) + ik.importer_type_id = importer_type_id + ik.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ishtar_common', '0259_ishtarsiteprofile_default_location_for_treatment'), + ] + + operations = [ + migrations.AlterModelOptions( + name='targetkey', + options={'ordering': ('target', 'key'), 'verbose_name': 'Import - Target key', 'verbose_name_plural': 'Import - Targets keys'}, + ), + migrations.AddField( + model_name='itemkey', + name='importer_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.ImporterType'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='default_location_for_treatment', + field=models.ForeignKey(blank=True, help_text='If provided, treatment forms have by default this location set. Furthermore if this location has an organization attached, this organization is set by default.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_warehouse.Warehouse', verbose_name='Default location for treatments'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='find_external_id', + field=models.TextField(default='{{get_first_base_find__context_record__external_id}}-{{label}}{% if upstream_count %}-{{upstream_count}}{% endif %}', help_text='Formula to manage find external ID. Change this with care. With incorrect formula, the application might be unusable and import of external data can be destructive.', verbose_name='Find external id'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='no_context_button', + field=models.ForeignKey(blank=True, help_text='If provided, a button is displayed on find add page to create a "No context" find', null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_context_records.ContextRecord', verbose_name='Context record for no context button'), + ), + migrations.RunPython(migrate_import_type), + migrations.RenameField( + model_name='itemkey', + old_name='importer', + new_name='ishtar_import' + ), + migrations.AlterField( + model_name='itemkey', + name='ishtar_import', + field=models.ForeignKey(blank=True, help_text='Specific key to an import', null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.Import'), + ), + ] diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index ed7cae234..4bea24ab5 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -675,22 +675,28 @@ class GeneralType(Cached, models.Model): self.generate_key(force=True) return obj - def add_key(self, key, force=False, importer=None, group=None, user=None): + def add_key(self, key, force=False, importer_type=None, ishtar_import=None, + group=None, user=None): ItemKey = apps.get_model("ishtar_common", "ItemKey") content_type = ContentType.objects.get_for_model(self.__class__) if ( - not importer + not ishtar_import and not force and ItemKey.objects.filter(key=key, content_type=content_type).count() ): return filtr = {"key": key, "content_type": content_type} - if group: + if importer_type: + filtr["importer_type"] = importer_type + elif group: filtr["group"] = group + filtr["importer_type"] = ishtar_import.importer_type if ishtar_import else None elif user: filtr["user"] = user + filtr["importer_type"] = ishtar_import.importer_type if ishtar_import else None else: - filtr["importer"] = importer + filtr["ishtar_import"] = ishtar_import + filtr["importer_type"] = ishtar_import.importer_type if ishtar_import else None if force: ItemKey.objects.filter(**filtr).exclude(object_id=self.pk).delete() filtr["object_id"] = self.pk @@ -700,18 +706,23 @@ class GeneralType(Cached, models.Model): for key in (slugify(self.label), self.txt_idx): self.add_key(key) - def get_keys(self, importer): + def get_keys(self, current_import): + importer_type = current_import.importer_type ItemKey = apps.get_model("ishtar_common", "ItemKey") keys = [self.txt_idx] content_type = ContentType.objects.get_for_model(self.__class__) base_q = Q(content_type=content_type, object_id=self.pk) - subquery = Q(importer__isnull=True, user__isnull=True, group__isnull=True) - subquery |= Q(user__isnull=True, group__isnull=True, importer=importer) - if importer.user: - subquery |= Q(user=importer.user, group__isnull=True, importer=importer) - if importer.associated_group: + subquery = Q(importer_type__isnull=True, user__isnull=True, + group__isnull=True) + subquery |= Q(user__isnull=True, group__isnull=True, + importer_type=importer_type) + if current_import.user: + subquery |= Q(user=current_import.user, group__isnull=True, + importer_type=importer_type) + if current_import.associated_group: subquery |= Q( - user__isnull=True, group=importer.associated_group, importer=importer + user__isnull=True, group=current_import.associated_group, + importer_type=importer_type ) q = ItemKey.objects.filter(base_q & subquery) for ik in q.exclude(key=self.txt_idx).all(): diff --git a/ishtar_common/models_imports.py b/ishtar_common/models_imports.py index a33b599c7..5bd230d6b 100644 --- a/ishtar_common/models_imports.py +++ b/ishtar_common/models_imports.py @@ -964,7 +964,7 @@ class TargetKeyGroup(models.Model): class TargetKey(models.Model): """ User's link between import source and ishtar database. - Also temporary used for GeneralType to point missing link before adding + Used for GeneralType to point missing link before adding them in ItemKey table. A targetkey connection can be create to be applied to one particular import (associated_import), one particular user (associated_user), @@ -975,17 +975,17 @@ class TargetKey(models.Model): target = models.ForeignKey( ImportTarget, related_name="keys", on_delete=models.CASCADE ) - key = models.TextField(_("Key")) + key = models.TextField(_("Key"), blank=True, default="") value = models.TextField(_("Value"), blank=True, null=True) is_set = models.BooleanField(_("Is set"), default=False) associated_import = models.ForeignKey( - "Import", blank=True, null=True, on_delete=models.SET_NULL + "Import", blank=True, null=True, on_delete=models.CASCADE ) associated_user = models.ForeignKey( - "IshtarUser", blank=True, null=True, on_delete=models.SET_NULL + "IshtarUser", blank=True, null=True, on_delete=models.CASCADE ) associated_group = models.ForeignKey( - TargetKeyGroup, blank=True, null=True, on_delete=models.SET_NULL + TargetKeyGroup, blank=True, null=True, on_delete=models.CASCADE ) class Meta: @@ -995,8 +995,8 @@ class TargetKey(models.Model): "associated_user", "associated_import", ) - verbose_name = _("Importer - Target key") - verbose_name_plural = _("Importer - Targets keys") + verbose_name = _("Import - Target key") + verbose_name_plural = _("Import - Targets keys") ordering = ("target", "key") ADMIN_SECTION = _("Imports") @@ -1022,34 +1022,36 @@ class TargetKey(models.Model): return return self.value - def save(self, *args, **kwargs): - obj = super(TargetKey, self).save(*args, **kwargs) + def create_itemkey(self, force_importer_type=False, force_all=False): if not self.value: - return obj + return v = None associated_model = self.target.associated_model - if associated_model and hasattr(self.target.associated_model, "add_key"): - # pk is given + if not associated_model or not hasattr(self.target.associated_model, "add_key"): + return + # pk is given + try: + v = self.target.associated_model.objects.get(pk=str(int(self.value))) + except (ValueError, self.target.associated_model.DoesNotExist): + # try with txt_idx try: - v = self.target.associated_model.objects.get(pk=str(int(self.value))) - except (ValueError, self.target.associated_model.DoesNotExist): - # try with txt_idx - try: - v = self.target.associated_model.objects.get( - txt_idx=str(self.value) - ) - except self.target.associated_model.DoesNotExist: - pass - if v: - keys = {} - if self.associated_group: - keys["group"] = self.associated_group - if self.associated_user: - keys["user"] = self.associated_user - else: - keys["importer"] = self.associated_import - v.add_key(self.key, **keys) - return obj + v = self.target.associated_model.objects.get( + txt_idx=str(self.value) + ) + except self.target.associated_model.DoesNotExist: + return + if force_all: + keys = {} + elif force_importer_type: + keys = {"importer_type": self.associated_import.importer_type} + else: + keys = {"ishtar_import": self.associated_import} + if self.associated_user: + keys["user"] = self.associated_user + elif self.associated_group: + keys["group"] = self.associated_group + v.add_key(self.key, **keys) + return TARGET_MODELS = [ @@ -2919,28 +2921,86 @@ class ImportColumnValue(models.Model): class ItemKey(models.Model): + """ + Importers: links Key -> Item + """ key = models.TextField(_("Key")) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) - object_id = models.PositiveIntegerField() + object_id = models.PositiveIntegerField(verbose_name=_("Value ID")) content_object = GenericForeignKey("content_type", "object_id") - importer = models.ForeignKey( + importer_type = models.ForeignKey( + ImporterType, + null=True, + blank=True, + verbose_name=_("Importer type"), + on_delete=models.CASCADE, + ) + ishtar_import = models.ForeignKey( Import, null=True, blank=True, - help_text=_("Specific key to an import"), - on_delete=models.SET_NULL, + verbose_name=_("Import"), + on_delete=models.CASCADE, ) user = models.ForeignKey( - "IshtarUser", blank=True, null=True, on_delete=models.SET_NULL + "IshtarUser", blank=True, null=True, on_delete=models.SET_NULL, + verbose_name=_("User") ) group = models.ForeignKey( - TargetKeyGroup, blank=True, null=True, on_delete=models.SET_NULL + TargetKeyGroup, blank=True, null=True, on_delete=models.SET_NULL, + verbose_name=_("Group") ) class Meta: - verbose_name = _("Import - Item key") - verbose_name_plural = _("Import - Item keys") + verbose_name = _("Importer - Item key") + verbose_name_plural = _("Importer - Item keys") ADMIN_SECTION = _("Imports") def __str__(self): return self.key + + @property + def content_slug(self): + item = self.content_object + if hasattr(item, "txt_idx"): + key = "txt_idx" + elif hasattr(item, "slug"): + key = "slug" + else: + key = "pk" + return getattr(item, key) + + def content_type_model(self): + return self.content_type.model + content_type_model.short_description = _("Content type model") + + def linked_to_all(self): + return not self.importer_type and not self.user and not self.group \ + and not self.ishtar_import + + linked_to_all.boolean = True + linked_to_all.short_description = _("Linked to all") + + def linked_to_importer_type(self): + return bool(self.importer_type) + + linked_to_importer_type.boolean = True + linked_to_importer_type.short_description = _("Linked to importer") + + def linked_to_importer(self): + return bool(self.ishtar_import) + + linked_to_importer.boolean = True + linked_to_importer.short_description = _("Linked to import") + + def linked_to_user(self): + return bool(self.user) + + linked_to_user.boolean = True + linked_to_user.short_description = _("Linked to user") + + def linked_to_group(self): + return bool(self.group) + + linked_to_group.boolean = True + linked_to_group.short_description = _("Linked to group") diff --git a/ishtar_common/serializers.py b/ishtar_common/serializers.py index 1469e13a1..3cbe20907 100644 --- a/ishtar_common/serializers.py +++ b/ishtar_common/serializers.py @@ -17,11 +17,12 @@ from .models_common import State, Department from archaeological_operations.models import ActType from ishtar_common.serializers_utils import ( - generic_get_results, archive_serialization, + CUSTOM_SERIALIZERS, + generic_get_results, generic_archive_files, - SERIALIZATION_VERSION, get_model_from_filename, + SERIALIZATION_VERSION, ) from archaeological_operations.serializers import ( @@ -466,7 +467,15 @@ def restore_serialized( or releasing_locks or (user and historized) ) - idx = -1 + idx = None + model_name = f"{model._meta.app_label}.{model._meta.model_name}" + if model_name in CUSTOM_SERIALIZERS: + current_serializer = CUSTOM_SERIALIZERS[model_name]() + for idx, values in enumerate(json.loads(data)): + current_serializer.save(values["fields"]) + if idx is not None: + result.append((model._meta.verbose_name, idx + 1)) + continue for idx, obj in enumerate(deserialize("json", data)): extra_attrs = {} if historized or hasattr(model, "locked"): @@ -514,6 +523,6 @@ def restore_serialized( obj.lock_user = None obj._no_move = True obj.save() - if idx >= 0: - result.append((model.__name__, idx + 1)) + if idx is not None: + result.append((model._meta.verbose_name, idx + 1)) return result diff --git a/ishtar_common/serializers_utils.py b/ishtar_common/serializers_utils.py index ada0a62cf..a4494d9c9 100644 --- a/ishtar_common/serializers_utils.py +++ b/ishtar_common/serializers_utils.py @@ -4,9 +4,12 @@ import datetime import json import importlib import os +from rest_framework.renderers import JSONRenderer +from rest_framework import serializers import tempfile from zipfile import ZipFile +from django.contrib.contenttypes.models import ContentType from django.contrib.sites.models import Site from django.core.serializers import serialize from django.db.models import Q @@ -113,6 +116,70 @@ def archive_serialization( return archive_name +class ItemKeySerializer(serializers.ModelSerializer): + app = serializers.SerializerMethodField() + model = serializers.SerializerMethodField() + content_slug = serializers.SerializerMethodField() + importer_type = serializers.SerializerMethodField() + + class Meta: + model = models.ItemKey + fields = ['key', 'app', 'model', 'content_slug', 'importer_type'] + + def get_content_slug(self, obj): + return obj.content_slug + + def get_app(self, obj): + return obj.content_type.app_label + + def get_model(self, obj): + return obj.content_type.model + + def get_importer_type(self, obj): + return obj.importer_type.slug if obj.importer_type else "" + + def save(self, data): + try: + ct = ContentType.objects.get( + app_label=data["app"], + model=data["model"], + ) + except ContentType.DoesNotExist: + return + model = ct.model_class() + if hasattr(model, "txt_idx"): + slug = "txt_idx" + elif hasattr(model, "slug"): + slug = "slug" + else: + slug = "pk" + try: + value = model.objects.get(**{slug: data["content_slug"]}) + except model.DoesNotExist: + return + importer_type = None + if data["importer_type"]: + try: + importer_type = models.ImporterType.objects.get( + slug=data["importer_type"] + ) + except models.ImporterType.DoesNotExist: + return + obj, created = models.ItemKey.objects.get_or_create( + key=data["key"], + content_type=ct, + importer_type=importer_type, + ishtar_import=None, + user=None, + group=None, + defaults={"object_id": value.pk} + ) + if not created: + obj.object_id = value.pk + obj.save() + return obj + + GENERIC_QUERYSET_FILTER = { "JsonDataSection": {"JsonDataField": "json_data_field__pk__in"}, "Regexp": { @@ -170,6 +237,8 @@ GENERIC_QUERYSET_FILTER = { } } +CUSTOM_SERIALIZERS = {"ishtar_common.itemkey": ItemKeySerializer} + def generic_get_results( model_list, dirname, no_geo=True, result_queryset=None, serialization_include=None @@ -212,13 +281,26 @@ def generic_get_results( q = q.filter(**{recursion + "__isnull": True}) key = (dirname, model_name) - result[key] = serialize( - "json", - q.distinct().all(), - indent=2, - use_natural_foreign_keys=True, - use_natural_primary_keys=True, - ) + model_name = f"{model._meta.app_label}.{model._meta.model_name}" + is_custom = model_name in CUSTOM_SERIALIZERS + if is_custom: + current_serializer = CUSTOM_SERIALIZERS[model_name] + result[key] = JSONRenderer().render( + [{"model": model_name, + "fields": current_serializer(item).data} + for item in q.distinct().all()] + ) + else: + result[key] = serialize( + "json", + q.distinct().all(), + indent=2, + use_natural_foreign_keys=True, + use_natural_primary_keys=True, + ) + if recursion and is_custom: + # TODO + raise NotImplementedError("Recursion not managed for this custom serializer") if recursion: serialized = [item["id"] for item in q.values("id").all()] @@ -278,6 +360,7 @@ def generic_get_results( for k in serialization_include[model.__name__]: if k in excluded_fields: excluded_fields.pop(excluded_fields.index(k)) + if excluded_fields: new_result = json.loads(result[key]) for idx in range(len(new_result)): |