From 73a818b87cad74273f7c48134fa0519abc9b3a7c Mon Sep 17 00:00:00 2001 From: Guido Longoni Date: Fri, 7 Jul 2023 00:34:47 +0200 Subject: [PATCH] uso il submodule --- .gitmodules | 6 + django/contatti_app/admin.py | 2 +- django/contatti_app/drilldown_autocomplete.py | 184 ------------------ .../admin/css/drilldown_autocomplete.css | 17 -- django/static/admin/js/autocomplete.js | 152 --------------- 5 files changed, 7 insertions(+), 354 deletions(-) create mode 100644 .gitmodules delete mode 100644 django/contatti_app/drilldown_autocomplete.py delete mode 100644 django/static/admin/css/drilldown_autocomplete.css delete mode 100644 django/static/admin/js/autocomplete.js diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2ecbc28 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "django/django-drilldown-autocomplete"] + path = django/django-drilldown-autocomplete + url = https://git.briq.it/Guido/django-drilldown-autocomplete +[submodule "django/drilldown_autocomplete"] + path = django/drilldown_autocomplete + url = https://git.briq.it/Guido/django-drilldown-autocomplete diff --git a/django/contatti_app/admin.py b/django/contatti_app/admin.py index 9d6161c..a652333 100644 --- a/django/contatti_app/admin.py +++ b/django/contatti_app/admin.py @@ -1,5 +1,6 @@ from dati_geo_app.admin import (AjaxAutocompleteListFilterModelAdmin, RicercaOrdinataMixin) +from drilldown_autocomplete import DrillDownAutocompleteAdmin from import_export.admin import ImportExportModelAdmin from polymorphic.admin import (PolymorphicChildModelAdmin, PolymorphicChildModelFilter, @@ -13,7 +14,6 @@ from django.core.paginator import Paginator from django.db.models import F from . import models -from .drilldown_autocomplete import DrillDownAutocompleteAdmin # Modified version of a GIST I found in a SO thread # cfr. http://masnun.rocks/2017/03/20/django-admin-expensive-count-all-queries/ diff --git a/django/contatti_app/drilldown_autocomplete.py b/django/contatti_app/drilldown_autocomplete.py deleted file mode 100644 index 919f030..0000000 --- a/django/contatti_app/drilldown_autocomplete.py +++ /dev/null @@ -1,184 +0,0 @@ -import json -from functools import update_wrapper - -from django.apps import apps -from django.contrib import admin -from django.contrib.admin.views.autocomplete import AutocompleteJsonView -from django.contrib.admin.widgets import AutocompleteMixin, AutocompleteSelect -from django.core.exceptions import FieldDoesNotExist, PermissionDenied -from django.db.models import Case, Max, Q, Value, When -from django.http import Http404, JsonResponse -from django.urls import path - - -class DrillDownAutocompleteJsonView(AutocompleteJsonView): - """Handle AutocompleteWidget's AJAX requests for data.""" - admin_context = None - - def process_request(self, request): - """ - Validate request integrity, extract and return request parameters. - - Since the subsequent view permission check requires the target model - admin, which is determined here, raise PermissionDenied if the - requested app, model or field are malformed. - - Raise Http404 if the target model admin is not configured properly with - search_fields. - """ - ( - term, - model_admin, - source_field, - to_field_name - ) = super().process_request(request) - - if 'filtered_by_dict' in request.GET: - try: - filtered_by_dict = json.loads( - request.GET.get("filtered_by_dict")) - except json.decoder.JSONDecodeError as e: - raise PermissionDenied from e - app_label = request.GET["app_label"] - model_name = request.GET["model_name"] - source_model = apps.get_model(app_label, model_name) - try: - drilldown_field = self.admin_context.get_drilldown_autocomplete_fields(request)[source_field.name] - filtered_by = set(drilldown_field['filtered_by']) - except KeyError as e: - raise PermissionDenied from e - if (set(filtered_by_dict.keys()) > filtered_by): - raise PermissionDenied - rel_paths = drilldown_field['relationship_path'] - target_model = source_field.remote_field.model - try: - for v in rel_paths.values(): - target_model._meta.get_field(v) - except FieldDoesNotExist as e: - raise PermissionDenied from e - self.target_model = target_model - self.filtered_by_dict = filtered_by_dict - self.drilldown_field = drilldown_field - self.drilldown_filter_data = { - rel_paths[k]: v for k, v in filtered_by_dict.items()} - - return term, model_admin, source_field, to_field_name - - def get_queryset(self): - """Return queryset based on ModelAdmin.get_search_results().""" - qs = super().get_queryset() - if hasattr(self, 'filtered_by_dict'): - dd_field = self.drilldown_field - drilldown_filter_conditions = Q(**self.drilldown_filter_data) - if dd_field.get('autoselect_on_singleton', False): - self.autoselect = False - if dd_field.get('included_only', False): - qs = qs.filter(drilldown_filter_conditions).annotate( - ddok=Value(1)) - else: - qs = qs.annotate(ddok=Max(Case(When(drilldown_filter_conditions, then=Value( - 1)), default=Value(0)))).order_by('-ddok', *qs.query.order_by) - if not getattr(self, 'autoselect', True) and qs.filter(ddok=1).count() == 1: - self.autoselect = True - else: - qs = qs.annotate(ddok=Value(1)) - return qs - - def serialize_result(self, obj, to_field_name): - """ - Convert the provided model object to a dictionary that is added to the - results list. - """ - out = super().serialize_result(obj, to_field_name) - if hasattr(obj, 'ddok'): - out['ddok'] = obj.ddok - if getattr(self, 'autoselect', False) and obj.ddok == 1: - out['autoselect'] = True - return out - - -class DrillDownAutocompleteMixin(AutocompleteMixin): - url_name = "%s:drilldown_autocomplete" - - -class DrillDownAutocompleteSelect(AutocompleteSelect, DrillDownAutocompleteMixin): - pass - - -class DrillDownAutocompleteAdmin(admin.options.BaseModelAdmin): - drilldown_autocomplete_fields = dict() - - class Media: - css = { - 'all': ('admin/css/drilldown_autocomplete.css',) - } - - def get_drilldown_autocomplete_fields(self, request): - return self.drilldown_autocomplete_fields - - def formfield_for_foreignkey(self, db_field, request, **kwargs): - """ - Get a form Field for a ForeignKey. - """ - db = kwargs.get("using") - - if "widget" not in kwargs: - daf = self.get_drilldown_autocomplete_fields(request) - if db_field.name in daf: - def get_fields_to_reset_recursive(daf, fields_to_reset, seen=None): - to_reset = set() - if seen is None: - seen = set() - for f in fields_to_reset: - if f in daf: - to_reset.add(f) - if f not in seen and 'reset_on_reset' in daf[f]: - seen.add(f) - to_reset.update(get_fields_to_reset_recursive( - daf, daf[f]['reset_on_reset'], seen)) - return to_reset - - attrs = {'data-drilldown_enabled': 1} - if 'filtered_by' in daf[db_field.name]: - attrs["data-filtered_by"] = json.dumps( - list(daf[db_field.name]['filtered_by'])) - if daf[db_field.name].get('included_only', False): - attrs['data-included_only'] = 1 - else: - if 'reset_on_excluded' in daf[db_field.name]: - reset_on_excluded = set( - daf[db_field.name]['reset_on_excluded']) - reset_on_excluded = get_fields_to_reset_recursive( - daf, reset_on_excluded) - attrs['data-reset_on_excluded'] = json.dumps( - list(reset_on_excluded)) - - if 'reset_on_included' in daf[db_field.name]: - reset_on_included = set( - daf[db_field.name]['reset_on_included']) - reset_on_included = get_fields_to_reset_recursive( - daf, reset_on_included) - attrs['data-reset_on_included'] = json.dumps( - list(reset_on_included)) - kwargs["widget"] = DrillDownAutocompleteSelect( - db_field, self.admin_site, attrs=attrs, using=db - ) - return super().formfield_for_foreignkey(db_field, request, **kwargs) - - def drilldown_autocomplete_view(self, request): - return DrillDownAutocompleteJsonView.as_view(admin_site=self.admin_site, admin_context=self)(request) - - def get_urls(self): - def wrap(view, cacheable=False): - def wrapper(*args, **kwargs): - return self.admin_site.admin_view(view, cacheable)(*args, **kwargs) - - wrapper.admin_site = self - return update_wrapper(wrapper, view) - - urls = super().get_urls() - drilldown_urls = [ - path("drilldown/", wrap(self.drilldown_autocomplete_view), - name="drilldown_autocomplete"), - ] - return drilldown_urls + urls diff --git a/django/static/admin/css/drilldown_autocomplete.css b/django/static/admin/css/drilldown_autocomplete.css deleted file mode 100644 index 74b05b7..0000000 --- a/django/static/admin/css/drilldown_autocomplete.css +++ /dev/null @@ -1,17 +0,0 @@ -.select2-container--admin-autocomplete .select2-results__option[aria-selected=true].drilldown_ok:not(:hover) { - background-color: var(--selected-row); - color: var(--body-fg); -} - -.select2-container--admin-autocomplete .select2-results__option[aria-selected=false].drilldown_ok:not(.select2-results__option--highlighted):not(:hover) { - background-color: var(--body-bg); - color: var(--body-fg); -} -.select2-container--admin-autocomplete .select2-results__option[aria-selected].drilldown_ko:not(:hover) { - background-color: #888; - color: var(--body-fg); -} - -span.drilldown_ko { - font-style: italic; -} \ No newline at end of file diff --git a/django/static/admin/js/autocomplete.js b/django/static/admin/js/autocomplete.js deleted file mode 100644 index db8f4ad..0000000 --- a/django/static/admin/js/autocomplete.js +++ /dev/null @@ -1,152 +0,0 @@ -'use strict'; -{ - const $ = django.jQuery; - - $.fn.djangoAdminSelect2 = function() { - $.each(this, function(i, element) { - const select2_config = {}; - let filtered_by_fields; - let reset_on_something = false; - const reset_on_excluded = []; - const reset_on_included = []; - - if (element.dataset.hasOwnProperty('drilldown_enabled')) { - - if (element.dataset.hasOwnProperty('reset_on_included')) { - reset_on_included.push(...JSON.parse(element.dataset.reset_on_included)); - reset_on_something = true; - } - - if (element.dataset.hasOwnProperty('filtered_by')) { - filtered_by_fields = JSON.parse(element.dataset.filtered_by); - if (element.dataset.hasOwnProperty('reset_on_excluded')) { - reset_on_excluded.push(...JSON.parse(element.dataset.reset_on_excluded)); - reset_on_something = true; - } - - } - if (reset_on_something) { - element.drilldown_items = {}; - } - - select2_config.templateResult = (item, container)=>{ - let styleClass = ''; - - element.classList.add('drilldown'); - - if (item.ddok === 1) { - styleClass = 'drilldown_ok'; - } else { - styleClass = 'drilldown_ko'; - } - - container.classList.add(styleClass); - if (reset_on_something) { - element.drilldown_items[item.id] = item; - } - - if (item.hasOwnProperty('autoselect')) { - const includedOnly = element.dataset.included_only ?? false; - const dataLength = $(element).select2('data').length; - - if (includedOnly || dataLength == 0) { - $(element).select2("trigger", "select", { - data: item - }) - } - } - - return $(``).text(item.text); - } - } - - select2_config.ajax = { - data: (params)=>{ - const {fieldName, appLabel, modelName} = element.dataset; - const out = { - term: params.term, - page: params.page, - app_label: appLabel, - model_name: modelName, - field_name: fieldName - }; - - if (element.dataset.hasOwnProperty('drilldown_enabled')) { - - if (reset_on_something && (params.page ?? 1) < 2) { - element.drilldown_items = {}; - } - - if (element.dataset.hasOwnProperty('filtered_by')) { - - const filtered_by_dict = {}; - let some_obj = false; - - for (let i in filtered_by_fields) { - if (filtered_by_fields.hasOwnProperty(i)) { - const filtering_field = filtered_by_fields[i]; - const field_id = element.dataset.select2Id; - const filtering_field_id = `${field_id.slice(0, field_id.length - fieldName.length)}${filtering_field}`; - const filtering_value = document.querySelector(`[data-select2-id="${filtering_field_id}"].admin-autocomplete`).value; - - if (filtering_value !== '') { - filtered_by_dict[filtering_field] = filtering_value; - some_obj = true; - } - } - } - - if (some_obj) { - out.filtered_by_dict = JSON.stringify(filtered_by_dict); - } - } - } - - return out; - } - }; - - $(element).select2(select2_config); - - if (reset_on_something) { - $(element).on('select2:select', (ev) => { - const data = $(element).select2('data'); - - if (element.hasOwnProperty("drilldown_items") && Array.isArray(data) && data.length > 0) { - const item = element.drilldown_items[data[0].id]; - const ddok = item !== undefined ? item.ddok : undefined; - - if (ddok !== undefined) { - let all_fields_to_reset = ddok ? reset_on_included : reset_on_excluded; - - if (all_fields_to_reset.length > 0) { - all_fields_to_reset.forEach((field_to_reset)=>{ - const field_name = element.dataset.fieldName; - const field_id = element.dataset.select2Id; - const id_to_reset = `${field_id.slice(0, field_id.length - field_name.length)}${field_to_reset}`; - const element_to_reset = document.querySelector(`#${id_to_reset}.admin-autocomplete`); - $(element_to_reset).val(null).trigger('change'); - } - ); - } - } - } - } - ); - } - }); - return this; - } - ; - - $(function() { - // Initialize all autocomplete widgets except the one in the template - // form used when a new formset is added. - $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); - }); - - document.addEventListener('formset:added', (event)=>{ - $(event.target).find('.admin-autocomplete').djangoAdminSelect2(); - } - ); -}