diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2025-02-18 12:25:56 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2025-02-19 14:45:57 +0100 |
commit | 90b65123f6740eb6c5683f92f0c4d304c656c37b (patch) | |
tree | fe3efe470cf390fcd4b7c2bd0c7e1a1c34975405 /ishtar_common | |
parent | b554c71d78ca15fdcbc38e16500f38b8455e5479 (diff) | |
download | Ishtar-90b65123f6740eb6c5683f92f0c4d304c656c37b.tar.bz2 Ishtar-90b65123f6740eb6c5683f92f0c4d304c656c37b.zip |
✨ admin: improve Next/Previous buttons, importer columns - set default importer type and col number
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/admin.py | 157 | ||||
-rw-r--r-- | ishtar_common/templates/admin/change_form.html | 2 |
2 files changed, 92 insertions, 67 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 556e7572d..c9393e57e 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -49,6 +49,7 @@ from django.contrib.gis.geos.error import GEOSException from django.core.cache import cache from django.core.exceptions import FieldError, FieldDoesNotExist from django.core.serializers import serialize +from django.db import connection from django.db.models import Q from django.db.models.fields import ( BooleanField, @@ -73,7 +74,7 @@ from ishtar_common import models, models_common, models_rest from ishtar_common.apps import admin_site from ishtar_common.model_merging import merge_model_objects from ishtar_common.utils import API_MAIN_CONTENT_TYPES, get_cache, create_slug,\ - get_person_gdpr_log + get_person_gdpr_log, InlineClass from ishtar_common import forms as common_forms, forms_common as other_common_forms from ishtar_common.serializers import restore_serialized, IMPORT_MODEL_LIST @@ -1534,69 +1535,23 @@ class TownAdmin(ImportGEOJSONActionAdmin, ImportActionAdmin): admin_site.register(models_common.Town, TownAdmin) -class GeneralTypeAdmin(ChangeParentAdmin, ImportActionAdmin, ImportJSONActionAdmin): - search_fields = ( - "label", - "txt_idx", - "comment", - ) - list_filter = ("available",) - save_on_top = True - actions = [ - export_as_csv_action(), - serialize_type_action, - change_value("available", True, _("Make available")), - change_value("available", False, _("Make unavailable")), - ] - prepopulated_fields = {"txt_idx": ("label",)} - LIST_DISPLAY = ["label", "txt_idx", "available", "comment"] - extra_list_display = [] - CSV_FIELD_ORDER = [ - "id", - "label", - "txt_idx", - "parent", - "order", - "available", - "comment", - ] - - def get_list_display(self, request): - list_display = list(self.LIST_DISPLAY)[:] - if hasattr(self.model, "parent"): - list_display.insert(2, "parent") - return list_display + self.extra_list_display - - @csrf_protect_m +class PreviousNextAdmin: def get_changelist_queryset(self, request): - """ - Get the changelist queryset to be used in the change view. - Used by previous and next button. - Mainly a copy from: - django/contrib/admin/options.py ModelAdmin->changelist_view - """ - list_display = self.get_list_display(request) - list_display_links = self.get_list_display_links(request, list_display) - list_filter = self.get_list_filter(request) - search_fields = self.get_search_fields(request) - list_select_related = self.get_list_select_related(request) - sortable_by = self.get_sortable_by(request) - - cl = ChangeListForChangeView( - request, - self.model, - list_display, - list_display_links, - list_filter, - self.date_hierarchy, - search_fields, - list_select_related, - self.list_per_page, - self.list_max_show_all, - self.list_editable, - self, - sortable_by, - ) + # adapt GET to a changelist_view style + get = request.GET.get("_changelist_filters", []) + if isinstance(get, str): + get = [get] + self._current_query = {} + for value in get: + if "=" not in value: + continue + k, v = value.split("=") + self._current_query[k] = v + fake_request = InlineClass( + {"GET": self._current_query, "user": request.user, + "resolver_match": request.resolver_match} + ) # only set attributes needed + cl = self.get_changelist_instance(fake_request) return cl.get_queryset(request) def change_view(self, request, object_id, form_url="", extra_context=None): @@ -1631,10 +1586,42 @@ class GeneralTypeAdmin(ChangeParentAdmin, ImportActionAdmin, ImportJSONActionAdm # on modify current object do not match current criteria # next is the first item extra_context["next_item"] = first + return super().change_view(request, object_id, form_url, extra_context) - return super(GeneralTypeAdmin, self).change_view( - request, object_id, form_url, extra_context - ) + +class GeneralTypeAdmin(PreviousNextAdmin, ChangeParentAdmin, ImportActionAdmin, + ImportJSONActionAdmin): + search_fields = ( + "label", + "txt_idx", + "comment", + ) + list_filter = ("available",) + save_on_top = True + actions = [ + export_as_csv_action(), + serialize_type_action, + change_value("available", True, _("Make available")), + change_value("available", False, _("Make unavailable")), + ] + prepopulated_fields = {"txt_idx": ("label",)} + LIST_DISPLAY = ["label", "txt_idx", "available", "comment"] + extra_list_display = [] + CSV_FIELD_ORDER = [ + "id", + "label", + "txt_idx", + "parent", + "order", + "available", + "comment", + ] + + def get_list_display(self, request): + list_display = list(self.LIST_DISPLAY)[:] + if hasattr(self.model, "parent"): + list_display.insert(2, "parent") + return list_display + self.extra_list_display general_models = [ @@ -2295,7 +2282,7 @@ class ImportTargetInline(admin.TabularInline): form = ImportTargetForm -class ImporterColumnAdmin(admin.ModelAdmin): +class ImporterColumnAdmin(PreviousNextAdmin, admin.ModelAdmin): list_display = ( "label", "importer_type", @@ -2318,6 +2305,42 @@ class ImporterColumnAdmin(admin.ModelAdmin): inlines = (ImportTargetInline, ImporterDuplicateFieldInline) actions = [duplicate_importercolumn, shift_left, shift_right] + def get_changeform_initial_data(self, request): + """ + Get current importer type and the first available column + """ + initial = super().get_changeform_initial_data(request) + base_query = self.get_changelist_queryset(request) + importer_type_id = None + if base_query.exists(): + importer_type_id = base_query.values_list( + "importer_type_id", flat=True).all()[0] + if not importer_type_id: + importer_type_id = self._current_query.get("importer_type__id__exact", None) + if importer_type_id and base_query.exclude( + importer_type_id=importer_type_id).exists(): + # not only one importer_type_id in current queryset + return initial + try: + initial["importer_type"] = models.ImporterType.objects.get( + id=importer_type_id) + except models.ImporterType.DoesNotExist: + return initial + + with connection.cursor() as cursor: + query = """ + SELECT min(col_number) + 1 FROM ishtar_common_importercolumn ic_a + WHERE importer_type_id = %s AND NOT EXISTS ( + SELECT col_number FROM ishtar_common_importercolumn ic_b + WHERE ic_b.col_number = ic_a.col_number + 1 + AND importer_type_id = %s + )""" + cursor.execute(query, [importer_type_id, importer_type_id]) + row = cursor.fetchone() + if row: + initial["col_number"] = row[0] + return initial + admin_site.register(models.ImporterColumn, ImporterColumnAdmin) diff --git a/ishtar_common/templates/admin/change_form.html b/ishtar_common/templates/admin/change_form.html index f5c83faa6..9195a3245 100644 --- a/ishtar_common/templates/admin/change_form.html +++ b/ishtar_common/templates/admin/change_form.html @@ -19,6 +19,7 @@ <a href="{% add_preserved_filters history_url %}" class="historylink">{% trans "History" %}</a> </li> {% if has_absolute_url %}<li><a href="{{ absolute_url }}" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif %} + {% if previous_item or next_item %} <li>{% if previous_item %} <a href="{% url opts|admin_urlname:'change' previous_item %}{{get_attr}}"> {% trans "Previous" %} @@ -36,4 +37,5 @@ </a> {% endif %} </li> + {% endif %} {% endblock %} |