302 lines
11 KiB
Python
302 lines
11 KiB
Python
from django.contrib import admin
|
|
from django import forms
|
|
from django.core.cache import cache
|
|
from django.core.paginator import Paginator
|
|
from django.db.models import Count, Value, Case, When, Value
|
|
from django.db.models.functions import Concat
|
|
from . import models
|
|
from . import autocomplete_extras
|
|
from djaa_list_filter.admin import AjaxAutocompleteListFilterModelAdmin
|
|
from django.contrib.admin.views.main import ChangeList
|
|
|
|
# Modified version of a GIST I found in a SO thread
|
|
# cfr. http://masnun.rocks/2017/03/20/django-admin-expensive-count-all-queries/
|
|
class CachingPaginator(Paginator):
|
|
def _get_count(self):
|
|
if not hasattr(self, "_count"):
|
|
self._count = None
|
|
if self._count is None:
|
|
try:
|
|
key = "adm:{0}:count".format(
|
|
hash(self.object_list.query.__str__()))
|
|
self._count = cache.get(key, -1)
|
|
if self._count == -1:
|
|
self._count = super().count
|
|
cache.set(key, self._count, 60)
|
|
except:
|
|
self._count = len(self.object_list)
|
|
return self._count
|
|
count = property(_get_count)
|
|
|
|
def prefix_match_len(str1, str2):
|
|
tot = 0
|
|
for char1, char2 in zip(str1, str2):
|
|
if char1 == char2:
|
|
tot += 1
|
|
else:
|
|
break
|
|
return tot
|
|
|
|
class RicercaOrdinataChangeList(ChangeList):
|
|
# super() è django.contrib.admin.views.main.ChangeList
|
|
def get_queryset(self, request):
|
|
qs = super().get_queryset(request)
|
|
if not(hasattr(request, 'search_term') and hasattr(request, 'disable_default_ordering') and request.disable_default_ordering):
|
|
return qs
|
|
|
|
search_term_cf = request.search_term.casefold()
|
|
tok_q = set(x.strip()
|
|
for x in search_term_cf.split(' ') if x.strip())
|
|
search_cache = {x.pk: str(x) for x in qs}
|
|
scores = []
|
|
l_s_t = len(search_term_cf) or 1
|
|
for obj_pk, obj_str in search_cache.items():
|
|
m_l = prefix_match_len(
|
|
obj_str.casefold(), search_term_cf)
|
|
score_non_tok = m_l / max(l_s_t, len(obj_str))
|
|
tok = set(x.strip().casefold()
|
|
for x in obj_str.split(' ') if x.strip())
|
|
if tok and tok_q:
|
|
score_tok = sum(prefix_match_len(token1, token2) / len(token1)
|
|
for token1 in tok_q
|
|
for token2 in tok) / (len(tok_q) + len(tok))
|
|
else:
|
|
score_tok = 0
|
|
scores.append((-score_non_tok, -score_tok, obj_pk))
|
|
scores.sort()
|
|
rank_by_pk = {obj_pk: rank for rank,
|
|
(_, _, obj_pk) in enumerate(scores)}
|
|
whens = [When(pk=-1, then=None)]
|
|
for obj_pk, rank in rank_by_pk.items():
|
|
whens.append(When(pk=obj_pk, then=Value(rank)))
|
|
qs = qs.annotate(briq_search_results_rank=Case(*whens, default=None))
|
|
ordering = self.get_ordering(request,qs)
|
|
qs = qs.order_by('briq_search_results_rank',*ordering)
|
|
return qs
|
|
|
|
|
|
class RicercaOrdinataMixin(admin.ModelAdmin):
|
|
def get_changelist(self, *args, **kwargs):
|
|
return RicercaOrdinataChangeList
|
|
|
|
def get_search_results(self, request, qs, search_term):
|
|
qs, may_have_duplicates = super().get_search_results(
|
|
request, qs, search_term,
|
|
)
|
|
if search_term and qs:
|
|
request.disable_default_ordering = True
|
|
request.search_term = search_term
|
|
if not request.resolver_match._func_path.split('.')[-1].lower().startswith('changelist'):
|
|
search_term_cf = request.search_term.casefold()
|
|
tok_q = set(x.strip()
|
|
for x in search_term_cf.split(' ') if x.strip())
|
|
search_cache = {x.pk: str(x) for x in qs}
|
|
scores = []
|
|
l_s_t = len(search_term_cf) or 1
|
|
for obj_pk, obj_str in search_cache.items():
|
|
m_l = prefix_match_len(
|
|
obj_str.casefold(), search_term_cf)
|
|
score_non_tok = m_l / max(l_s_t, len(obj_str))
|
|
tok = set(x.strip().casefold()
|
|
for x in obj_str.split(' ') if x.strip())
|
|
if tok and tok_q:
|
|
score_tok = sum(prefix_match_len(token1, token2) / len(token1)
|
|
for token1 in tok_q
|
|
for token2 in tok) / (len(tok_q) + len(tok))
|
|
else:
|
|
score_tok = 0
|
|
scores.append((-score_non_tok, -score_tok, obj_pk))
|
|
scores.sort()
|
|
rank_by_pk = {obj_pk: rank for rank,
|
|
(_, _, obj_pk) in enumerate(scores)}
|
|
whens = [When(pk=-1, then=None)]
|
|
for obj_pk, rank in rank_by_pk.items():
|
|
whens.append(When(pk=obj_pk, then=Value(rank)))
|
|
qs = qs.annotate(briq_search_results_rank=Case(*whens, default=None))
|
|
qs = qs.order_by('briq_search_results_rank')
|
|
return qs, may_have_duplicates
|
|
|
|
|
|
# # Main reusable Admin class for only viewing
|
|
# class ViewAdminMixin(admin.ModelAdmin):
|
|
# def has_add_permission(self, request):
|
|
# return False
|
|
#
|
|
# def has_change_permission(self, request, obj=None):
|
|
# return False
|
|
#
|
|
# def has_delete_permission(self, request, obj=None):
|
|
# return False
|
|
|
|
|
|
@admin.register(models.Comune)
|
|
class ComuneAdmin(RicercaOrdinataMixin, AjaxAutocompleteListFilterModelAdmin):
|
|
list_per_page = 15
|
|
paginator = CachingPaginator
|
|
show_full_result_count = False
|
|
fields=('nome','provincia','cap','codice_istat','codice_nazionale',)
|
|
search_fields = ('nome','cap__codice__exact','codice_istat__exact','codice_nazionale__iexact',)
|
|
autocomplete_fields = ('provincia','cap',)
|
|
list_display = ('nome', 'provincia','regione_key','lista_cap',)
|
|
ordering = ('nome','provincia_id',)
|
|
autocomplete_list_filter = ('provincia',)
|
|
list_filter = ('provincia__regione_id',)
|
|
|
|
def regione_key(self, obj):
|
|
return obj.provincia.regione_id
|
|
regione_key.short_description = 'Regione'
|
|
regione_key.admin_order_field = 'regione_id'
|
|
|
|
def get_queryset(self, request):
|
|
queryset = super().get_queryset(request).prefetch_related('provincia').prefetch_related('cap')
|
|
return queryset
|
|
|
|
def lista_cap(self,obj):
|
|
lista = sorted((c.codice for c in obj.cap.all()),key=int)
|
|
aggr_cap=''
|
|
if len(lista) > 0:
|
|
gruppi = [[lista[0]]*2]
|
|
for i in lista[1:]:
|
|
if int(i)-1 == int(gruppi[-1][1]):
|
|
gruppi[-1][1] = i
|
|
else:
|
|
gruppi.append([i]*2)
|
|
aggr_cap=', '.join(f'{str(g[0])}-{str(g[1])}' if g[1]!=g[0] else str(g[0]) for g in gruppi)
|
|
return aggr_cap
|
|
|
|
# from django.db.models.fields.related import ManyToManyRel
|
|
# import django.db.models as dj_models
|
|
|
|
# asd = dj_models.ManyToManyField(models.Comune, through=models.Comune.cap.through)
|
|
# asd.model = models.CAP
|
|
# asd.name = "comuni2"
|
|
# asd.remote_field = models.Comune.cap.through._meta.get_field('comune')
|
|
# models.CAP._meta.add_field(asd)
|
|
|
|
class CAPAdminForm(forms.ModelForm):
|
|
#asd = ManyToManyRel(models.Comune.cap, to=models.Comune, related_name="asd",through=models.Comune.cap.through, related_query_name="comuni")
|
|
comuni = forms.ModelMultipleChoiceField(
|
|
models.Comune.objects.all(),
|
|
#widget=admin.widgets.AutocompleteSelectMultiple(models.CAP._meta.get_field("comuni2"), admin_site= None),
|
|
widget=admin.widgets.FilteredSelectMultiple('Comune', False),
|
|
required=False,
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
#print(self.base_fields)
|
|
if self.instance.pk:
|
|
self.initial['comuni'] = self.instance.comuni.values_list('pk', flat=True)
|
|
|
|
def save(self, *args, **kwargs):
|
|
instance = super().save(*args, **kwargs)
|
|
if instance.pk:
|
|
instance.comuni.clear()
|
|
instance.comuni.add(*self.cleaned_data['comuni'])
|
|
return instance
|
|
|
|
class Meta:
|
|
model = models.CAP
|
|
fields = "__all__"
|
|
|
|
|
|
|
|
@admin.register(models.CAP)
|
|
class CAPAdmin(RicercaOrdinataMixin, AjaxAutocompleteListFilterModelAdmin):
|
|
list_per_page = 15
|
|
paginator = CachingPaginator
|
|
show_full_result_count = False
|
|
fields=('codice', 'comuni')
|
|
search_fields=('codice','comuni__nome__iexact')
|
|
ordering = ('codice',)
|
|
list_display = ('codice','numero_comuni','lista_comuni',)
|
|
list_filter = ('comuni__provincia__regione_id',)
|
|
|
|
form = CAPAdminForm
|
|
# def get_form(self, request, obj=None, change=False, **kwargs):
|
|
# form = super().get_form(request, obj, change, **kwargs)
|
|
# form.base_fields['comuni'].widget.admin_site = self.admin_site
|
|
# return form
|
|
|
|
def get_queryset(self, request):
|
|
queryset = super().get_queryset(request).prefetch_related('comuni')
|
|
queryset = queryset.annotate(
|
|
conteggio_comuni=Count('comuni')
|
|
)
|
|
return queryset
|
|
|
|
def numero_comuni(self, obj):
|
|
return obj.conteggio_comuni
|
|
numero_comuni.admin_order_field = 'conteggio_comuni'
|
|
|
|
def lista_comuni(self,obj):
|
|
return ', '.join(str(c) for c in obj.comuni.all())
|
|
|
|
|
|
@admin.register(models.Provincia)
|
|
class ProvinciaAdmin(RicercaOrdinataMixin, admin.ModelAdmin):
|
|
list_per_page = 15
|
|
paginator = CachingPaginator
|
|
show_full_result_count = False
|
|
search_fields = ('sigla', 'nome_esteso',)
|
|
list_display = ('nome_esteso', 'sigla', 'numero_comuni', 'regione_key',)
|
|
list_filter = ('regione_id',)
|
|
#ordering = ('regione_id', 'nome_esteso',)
|
|
|
|
def regione_key(self, obj):
|
|
return obj.regione_id
|
|
regione_key.short_description = 'Regione'
|
|
regione_key.admin_order_field = 'regione_id'
|
|
|
|
def get_queryset(self, request):
|
|
queryset = super().get_queryset(request)
|
|
queryset = queryset.annotate(
|
|
conteggio_comuni=Count('comuni')
|
|
)
|
|
return queryset
|
|
|
|
def numero_comuni(self, obj):
|
|
return obj.conteggio_comuni
|
|
numero_comuni.admin_order_field = 'conteggio_comuni'
|
|
|
|
|
|
@admin.register(models.Regione)
|
|
class RegioneAdmin(RicercaOrdinataMixin, admin.ModelAdmin):
|
|
# list_per_page = 15
|
|
# paginator = CachingPaginator
|
|
# show_full_result_count = False
|
|
search_fields = ('nome',)
|
|
list_display = ('nome', 'numero_province',)
|
|
ordering = ('nome',)
|
|
|
|
def get_queryset(self, request):
|
|
queryset = super().get_queryset(request)
|
|
queryset = queryset.annotate(
|
|
conteggio_province=Count('province')
|
|
)
|
|
return queryset
|
|
|
|
def numero_province(self, obj):
|
|
return obj.conteggio_province
|
|
numero_province.admin_order_field = 'conteggio_province'
|
|
|
|
|
|
@admin.register(models.DUG)
|
|
class DUGAdmin(RicercaOrdinataMixin, admin.ModelAdmin):
|
|
list_per_page = 15
|
|
paginator = CachingPaginator
|
|
show_full_result_count = False
|
|
fields=('nome',)
|
|
search_fields=('nome',)
|
|
ordering = ('nome',)
|
|
list_display = ('nome',)
|
|
|
|
@admin.register(models.Nazione)
|
|
class NazioneAdmin(admin.ModelAdmin):
|
|
# resource = resources.NazioneResource
|
|
# list_per_page = 15
|
|
# paginator = CachingPaginator
|
|
# show_full_result_count = False
|
|
search_fields = ('descrizione','codifica',)
|
|
pass
|