uso il submodule

my-submodulepoetico
Guido Longoni 2023-07-07 00:34:47 +02:00
parent 93ab4aace2
commit 73a818b87c
5 changed files with 7 additions and 354 deletions

6
.gitmodules vendored 100644
View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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;
}

View File

@ -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 $(`<span class="${styleClass}"></span>`).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();
}
);
}