summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
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
commit90b65123f6740eb6c5683f92f0c4d304c656c37b (patch)
treefe3efe470cf390fcd4b7c2bd0c7e1a1c34975405 /ishtar_common
parentb554c71d78ca15fdcbc38e16500f38b8455e5479 (diff)
downloadIshtar-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.py157
-rw-r--r--ishtar_common/templates/admin/change_form.html2
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 %}