Last active
April 22, 2018 20:49
-
-
Save andreif/d00ffb67a98e9a9013934df6ab6f24fa to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| list_filter = (('article__product', SearchableFilter), | |
| ('article', SearchableFilter)) | |
| def lookup_allowed(self, lookup, value): | |
| return lookup in [ | |
| 'article__id__exact', | |
| 'article__product__id__exact', | |
| ] or super(LicenseAdmin, self).lookup_allowed(lookup, value) | |
| """ | |
| from django.contrib.admin import RelatedFieldListFilter | |
| from django.core.urlresolvers import reverse | |
| class SearchableFilter(RelatedFieldListFilter): | |
| template = 'admin/searchable_filter.html' | |
| def choices(self, cl): | |
| ch = list(super(SearchableFilter, self).choices(cl)) | |
| return ch[:1] + list(sorted(ch[1:], key=lambda x: x['display'].strip())) | |
| def admin_link(obj, name=None): | |
| if isinstance(obj, str): | |
| def _admin_link(instance): | |
| from django.db.models import Manager | |
| instance = getattr(instance, obj) | |
| if isinstance(instance, Manager): | |
| instance = instance.all() | |
| return admin_link(instance) | |
| _admin_link.allow_tags = True | |
| _admin_link.short_description = str(obj).replace('_', ' ').capitalize() | |
| return _admin_link | |
| if hasattr(obj, '__iter__'): | |
| return '<br>'.join(map(admin_link, obj)) | |
| if obj: | |
| return '<a class="changelink" style="color: #334" href="%s">%s</a>' % ( | |
| reverse('admin:%s_%s_change' % ( | |
| obj._meta.app_label, | |
| obj._meta.module_name, | |
| ), args=( | |
| obj.pk, | |
| )), | |
| name or obj) | |
| # coding=utf-8 | |
| from django.contrib import admin | |
| from django.contrib.admin.models import LogEntry | |
| from django.contrib.auth.decorators import user_passes_test, REDIRECT_FIELD_NAME | |
| from django.contrib.contenttypes.admin import GenericTabularInline | |
| from django.contrib.contenttypes.fields import GenericForeignKey | |
| from django.core.urlresolvers import reverse | |
| from django.db.models import Count, Q | |
| from django.utils.translation import ugettext_lazy as _ | |
| GenericForeignKey('content_type', 'object_id')\ | |
| .contribute_to_class(LogEntry, 'content_object') | |
| class LogEntryInline(GenericTabularInline): | |
| model = LogEntry | |
| fields = readonly_fields = ['action_time', 'user', 'change_message'] | |
| can_delete = False | |
| extra = 0 | |
| def has_add_permission(self, request): | |
| return False | |
| def admin_url(instance): | |
| if isinstance(instance, tuple): | |
| if len(instance) == 2: | |
| return reverse('admin:%s_%s_changelist' % instance) | |
| app, model, pk = instance | |
| else: | |
| app, model, pk = (instance._meta.app_label, | |
| instance._meta.model_name, | |
| instance.pk) | |
| url_name = 'admin:%s_%s_change' % (app, model) | |
| return reverse(url_name, args=(pk,)) | |
| def admin_link(instance, text=None, query=None): | |
| if callable(text): | |
| text = text(instance) | |
| if not text: | |
| text = instance | |
| if isinstance(text, tuple): | |
| text = text[-1] | |
| return '<a href="%s">%s</a>' % (admin_url(instance) + (query or ''), text) | |
| class ChoiceFilter(admin.SimpleListFilter): | |
| field_name = None | |
| @property | |
| def title(self): | |
| return _(self.field_name.replace('_', ' ')) | |
| @property | |
| def parameter_name(self): | |
| return self.field_name + '__choice' | |
| def get_filter_queryset(self, request, model_admin): | |
| params = request.GET.copy() | |
| if self.parameter_name in params: | |
| del params[self.parameter_name] | |
| fake_request = type('fake_request', (), { | |
| 'GET': params, | |
| 'resolver_match': request.resolver_match, | |
| 'user': request.user}) | |
| list_display = model_admin.get_list_display(request=request) | |
| list_filter = [f for f in model_admin.get_list_filter(request=request) | |
| if getattr(f, 'field_name', None) != self.field_name] | |
| return model_admin.get_changelist(request=request)( | |
| request=fake_request, | |
| model=model_admin.model, | |
| list_display=list_display, | |
| list_display_links=model_admin.get_list_display_links(request=request, list_display=list_display), | |
| list_filter=list_filter, | |
| date_hierarchy=model_admin.date_hierarchy, | |
| search_fields=model_admin.search_fields, | |
| list_select_related=model_admin.list_select_related, | |
| list_per_page=model_admin.list_per_page, | |
| list_max_show_all=model_admin.list_max_show_all, | |
| list_editable=model_admin.list_editable, | |
| model_admin=model_admin, | |
| ).queryset | |
| def get_label(self, value, count): | |
| if value is None: | |
| value = '(None)' | |
| return "%s (%d)" % (value, count) | |
| def lookups(self, request, model_admin): | |
| f = self.field_name | |
| ignore_attr = '__ignore_choice_filter_lookups' | |
| if getattr(model_admin, ignore_attr, False): | |
| return () | |
| setattr(model_admin, ignore_attr, True) | |
| qs = self.get_filter_queryset(request, model_admin) | |
| setattr(model_admin, ignore_attr, False) | |
| null_count = qs.filter(**{f + '__isnull': True}).count() | |
| qs = qs.filter(**{f + '__isnull': False}) | |
| ch = tuple( | |
| (k, self.get_label(k, v)) | |
| for k, v in qs.values(f).annotate(Count(f)).order_by(f) | |
| .values_list(f, f + '__count') | |
| ) | |
| ch = sorted(ch, key=lambda x: x[1]) | |
| if null_count: | |
| ch += (('__isnull', self.get_label(None, null_count)),) | |
| return ch | |
| def queryset(self, request, queryset): | |
| # TODO: fix unselected bug | |
| values = request.GET.getlist(self.parameter_name) | |
| if not values: | |
| return queryset | |
| q = Q(**{self.field_name + '__isnull': True}) if '__isnull' in values else Q() | |
| values = filter(lambda x: x != '__isnull', values) | |
| q = q | Q(**{self.field_name + '__in': values}) if values else q | |
| return queryset.filter(q) | |
| def choice_filter(field_name, get_label=None, get_value=None): | |
| attrs = {'field_name': field_name} | |
| if get_value and not get_label: | |
| get_label = lambda v, c: "%s (%s)" % (get_value(v), c) | |
| if get_label: | |
| attrs['get_label'] = staticmethod(get_label) | |
| return type(field_name + 'ChoiceFilter', (ChoiceFilter,), attrs) | |
| def staff_required(func=None, all_permissions=(), any_permissions=(), | |
| login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): | |
| """ | |
| Decorator for views that checks that the user is logged in, is active, | |
| is staff and has permissions redirecting to the log-in page if necessary. | |
| """ | |
| actual_decorator = user_passes_test( | |
| lambda u: u.is_authenticated() and u.is_active and u.is_staff and ( | |
| not all_permissions or all(map(all_permissions, u.has_perm))) and ( | |
| not any_permissions or any(map(any_permissions, u.has_perm))), | |
| login_url=login_url, | |
| redirect_field_name=redirect_field_name | |
| ) | |
| if func: | |
| return actual_decorator(func) | |
| return actual_decorator |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {% load i18n %} | |
| <div class="searchable-filter" id="searchable-filter-{{ spec.lookup_kwarg }}"> | |
| <h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %} | |
| <span>({{ choices|length }})</span></h3> | |
| <ul> | |
| {% for choice in choices %} | |
| {% if forloop.first or choice.selected %} | |
| <li{% if choice.selected %} class="selected"{% endif %}> | |
| <a href="{{ choice.query_string|iriencode }}">{{ choice.display }}</a></li> | |
| {% endif %} | |
| {% endfor %} | |
| <li> | |
| <input type="text" placeholder="Filter {{ title }} list..."> | |
| </li> | |
| </ul> | |
| <ul class="searchable-filter-list"> | |
| {% for choice in choices %} | |
| {% if not forloop.first and not choice.selected %} | |
| <li{% if choice.selected %} class="selected"{% endif %}> | |
| <a href="{{ choice.query_string|iriencode }}">{{ choice.display }}</a></li> | |
| {% endif %} | |
| {% endfor %} | |
| <li class="not-found" style="display: none">(nothing matches)</li> | |
| </ul> | |
| </div> | |
| <style> | |
| DIV.searchable-filter H3 SPAN { | |
| font-weight: normal; | |
| } | |
| DIV.searchable-filter INPUT { | |
| width: 137px; | |
| margin-left: -3px; | |
| } | |
| DIV.searchable-filter UL.searchable-filter-list { | |
| max-height: 300px; | |
| overflow-y: scroll; | |
| margin: -7px 0 0 !important; | |
| padding: 5px 0 5px 10px !important; | |
| box-shadow: 0 4px 10px -10px #000 inset, | |
| 0 -4px 10px -10px #000 inset; | |
| background: #e9e9e9; | |
| } | |
| DIV.searchable-filter UL.searchable-filter-list LI.not-found { | |
| padding: 10px; | |
| color: #AAA; | |
| } | |
| </style> | |
| <script> | |
| document.querySelectorAll('DIV.searchable-filter INPUT').forEach(function(i) { | |
| i.addEventListener('keyup', function(e) { | |
| e = e || window.event; | |
| var input = e.target; | |
| var div = input.parentNode.parentNode.parentNode; | |
| var v = input.value.trim(); | |
| var found = false; | |
| div.querySelectorAll('UL.searchable-filter-list LI').forEach(function (li) { | |
| if (li.classList.contains('not-found')) { | |
| return | |
| } | |
| var show = v.length == 0 || li.querySelector('A').innerText.toLowerCase().indexOf(v.toLowerCase()) != -1; | |
| li.style.display = show ? 'inherit' : 'none'; | |
| found = found || show; | |
| }); | |
| div.querySelector('UL.searchable-filter-list LI.not-found').style.display = found ? 'none' : 'inherit'; | |
| return false | |
| }, false); | |
| }) | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment