diff --git a/dataedit/migrations/0046_alter_view_unique_together_remove_view_is_default.py b/dataedit/migrations/0046_alter_view_unique_together_remove_view_is_default.py new file mode 100644 index 000000000..81d704279 --- /dev/null +++ b/dataedit/migrations/0046_alter_view_unique_together_remove_view_is_default.py @@ -0,0 +1,57 @@ +# Generated by Django 5.1.15 on 2026-01-26 10:58 +__license__ = """ +SPDX-FileCopyrightText: Christian Winger +SPDX-License-Identifier: AGPL-3.0-or-later +""" # noqa: 501 + +import logging + +from django.db import migrations +from django.db.models import Count, Max + +logger = logging.getLogger("oeplatform") + + +def remove_duplicate_views(apps, schema_editor): + """remove duplicates of (table, type, name). + + But keep last instance + """ + + View = apps.get_model("dataedit", "View") + + duplicate_groups = ( + View.objects.values("table", "type", "name") # group by + .annotate(keep_id=Max("id"), count=Count("id")) + .filter(count__gt=1) + ) + + for d in duplicate_groups: + for view in View.objects.filter( + table=d["table"], + type=d["type"], + name=d["name"], + ).exclude(id=d["keep_id"]): + logging.warning(f"removing view: {view}") + view.delete() + + +def remove_duplicate_views_reverse(apps, schema_editor): + # do nothing + pass + + +class Migration(migrations.Migration): + atomic = False + + dependencies = [ + ("dataedit", "0045_alter_embargo_table"), + ] + + operations = [ + migrations.RunPython(remove_duplicate_views, remove_duplicate_views_reverse), + migrations.AlterUniqueTogether( + name="view", + unique_together={("table", "type", "name")}, + ), + ] diff --git a/dataedit/models.py b/dataedit/models.py index 119fd266c..c386a0c24 100644 --- a/dataedit/models.py +++ b/dataedit/models.py @@ -25,7 +25,7 @@ from django.contrib.postgres.search import SearchVectorField from django.core.exceptions import ValidationError -from django.db import models +from django.db import models, transaction from django.db.models import ( BooleanField, CharField, @@ -370,7 +370,6 @@ def get_readable_table_name(self) -> str: ) except Exception: - return self.name def validate_open_data_license( @@ -511,6 +510,33 @@ class View(models.Model): def __str__(self): return '{}--"{}"({})'.format(self.table, self.name, self.type.upper()) + class Meta: + unique_together = [("table", "type", "name")] + + @classmethod + def get_or_create_default( + cls, table: str, type: str = "table", name: str = "default" + ) -> "View": + with transaction.atomic(): + # technically, multiple views per table can be default (or none). + view = View.objects.filter(is_default=True, table=table).last() + if view: + return view + # its possible that we have a view named "default", that is not + # marked as is_default=True + view = View.objects.filter(table=table, type=type, name=name).last() + if view is not None: + # make it default for next time + view.is_default = True + view.save() + return view + + # create a new one + view = View.objects.create( + table=table, type=type, name=name, is_default=True + ) + return view + class Filter(models.Model): column = CharField(max_length=100, null=False) @@ -708,13 +734,12 @@ def set_version_of_metadata_for_review(self, table: str, *args, **kwargs): return ( True, - f"Set current version of table's: '{table}' " "oemetadata for review.", + f"Set current version of table's: '{table}' oemetadata for review.", ) return ( False, - f"This tables (name: {table}) review " - "already got a version of oemetadata.", + f"This tables (name: {table}) review already got a version of oemetadata.", ) def update_all_table_peer_reviews_after_table_moved(self, *args, topic, **kwargs): diff --git a/dataedit/urls.py b/dataedit/urls.py index bda0f5b2a..8275a39be 100644 --- a/dataedit/urls.py +++ b/dataedit/urls.py @@ -68,14 +68,18 @@ name="table-view-save", ), re_path( - r"^(?P