Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for filtering of multiple values + fix bug farhan0581#15 for Django 2.2 #18

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions admin_auto_filters/filters.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
from django.contrib.admin.widgets import AutocompleteSelect as Base
from django.contrib.admin.widgets import AutocompleteSelectMultiple
from django import forms
from django.contrib import admin
from django.core.exceptions import ImproperlyConfigured
from django.db.models.fields.related_descriptors import ReverseManyToOneDescriptor, ManyToManyDescriptor
from django.forms.widgets import Media, MEDIA_TYPES


class AutocompleteSelect(Base):
def __init__(self, rel, admin_site, attrs=None, choices=(), using=None, custom_url=None):
self.custom_url = custom_url
super().__init__(rel, admin_site, attrs, choices, using)

def get_url(self):
return self.custom_url if self.custom_url else super().get_url()
from django.db.models import Q


class AutocompleteFilter(admin.SimpleListFilter):
Expand All @@ -23,7 +15,7 @@ class AutocompleteFilter(admin.SimpleListFilter):
is_placeholder_title = False
widget_attrs = {}
rel_model = None
form_field = forms.ModelChoiceField
form_field = forms.ModelMultipleChoiceField

class Media:
js = (
Expand All @@ -36,17 +28,17 @@ class Media:
}

def __init__(self, request, params, model, model_admin):
self.parameter_name = '{}__{}__exact'.format(self.field_name, self.field_pk)
self.parameter_name = '{}__{}__in'.format(
self.field_name, self.field_pk)
super().__init__(request, params, model, model_admin)

if self.rel_model:
model = self.rel_model

remote_field = model._meta.get_field(self.field_name).remote_field

widget = AutocompleteSelect(remote_field,
model_admin.admin_site,
custom_url=self.get_autocomplete_url(request, model_admin),)
widget = AutocompleteSelectMultiple(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to provide the functionality for custom url for autocomplete, but it would be completely removed in this change. Require changes here.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be done in this PR: #81

remote_field, model_admin.admin_site)
form_field = self.get_form_field()
field = form_field(
queryset=self.get_queryset_for_field(model, self.field_name),
Expand All @@ -63,7 +55,7 @@ def __init__(self, request, params, model, model_admin):
attrs['data-Placeholder'] = self.title
self.rendered_widget = field.widget.render(
name=self.parameter_name,
value=self.used_parameters.get(self.parameter_name, ''),
value=self.value(),
attrs=attrs
)

Expand All @@ -82,14 +74,25 @@ def get_form_field(self):
return self.form_field

def _add_media(self, model_admin, widget):

if not hasattr(model_admin, 'Media'):
raise ImproperlyConfigured('Add empty Media class to %s. Sorry about this bug.' % model_admin)
raise ImproperlyConfigured(
'Add empty Media class to %s. Sorry about this bug.' % model_admin)

def _get_media(obj):
return Media(media=getattr(obj, 'Media', None))

media = _get_media(model_admin) + widget.media + _get_media(AutocompleteFilter) + _get_media(self)
class FilterMedia:
js = (
'admin/js/jquery.init.js',
'django-admin-autocomplete-filter/js/autocomplete_filter_qs.js',
)
css = {
'screen': (
'django-admin-autocomplete-filter/css/autocomplete-fix.css',
),
}

media = _get_media(model_admin) + widget.media + Media(FilterMedia)

for name in MEDIA_TYPES:
setattr(model_admin.Media, name, getattr(media, "_" + name))
Expand All @@ -100,12 +103,15 @@ def has_output(self):
def lookups(self, request, model_admin):
return ()

def value(self):
return self.used_parameters.get(self.parameter_name).split(',') if self.used_parameters.get(self.parameter_name) else []
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this be better with classical if - else block?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I changed it.
Also had to add var jQuery = django.jQuery, $ = jQuery; to the beginning of the js file for it to work consistently.
To fix the bug of having to have an empty Media class in the Admin class, it probably would be better to attach the media to a form class surrounding the select as in django-admin-rangefilter.
It does not seem correct to have a select outside of a form anyway.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My recommendation would be

parameter_name = self.used_parameters.get(self.parameter_name)
if parameter_name:
    return parameter_name.split(',')
return []


def queryset(self, request, queryset):
if self.value():
return queryset.filter(**{self.parameter_name: self.value()})
else:
return queryset

def get_autocomplete_url(self, request, model_admin):
'''
Hook to specify your custom view for autocomplete,
Expand Down