1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549 |
- import datetime
- import sys
- import unittest
- from django.contrib.admin import (
- AllValuesFieldListFilter, BooleanFieldListFilter, EmptyFieldListFilter,
- ModelAdmin, RelatedOnlyFieldListFilter, SimpleListFilter, site,
- )
- from django.contrib.admin.options import IncorrectLookupParameters
- from django.contrib.auth.admin import UserAdmin
- from django.contrib.auth.models import User
- from django.core.exceptions import ImproperlyConfigured
- from django.test import RequestFactory, TestCase, override_settings
- from .models import (
- Book, Bookmark, Department, Employee, ImprovedBook, TaggedItem,
- )
- def select_by(dictlist, key, value):
- return [x for x in dictlist if x[key] == value][0]
- class DecadeListFilter(SimpleListFilter):
- def lookups(self, request, model_admin):
- return (
- ('the 80s', "the 1980's"),
- ('the 90s', "the 1990's"),
- ('the 00s', "the 2000's"),
- ('other', "other decades"),
- )
- def queryset(self, request, queryset):
- decade = self.value()
- if decade == 'the 80s':
- return queryset.filter(year__gte=1980, year__lte=1989)
- if decade == 'the 90s':
- return queryset.filter(year__gte=1990, year__lte=1999)
- if decade == 'the 00s':
- return queryset.filter(year__gte=2000, year__lte=2009)
- class NotNinetiesListFilter(SimpleListFilter):
- title = "Not nineties books"
- parameter_name = "book_year"
- def lookups(self, request, model_admin):
- return (
- ('the 90s', "the 1990's"),
- )
- def queryset(self, request, queryset):
- if self.value() == 'the 90s':
- return queryset.filter(year__gte=1990, year__lte=1999)
- else:
- return queryset.exclude(year__gte=1990, year__lte=1999)
- class DecadeListFilterWithTitleAndParameter(DecadeListFilter):
- title = 'publication decade'
- parameter_name = 'publication-decade'
- class DecadeListFilterWithoutTitle(DecadeListFilter):
- parameter_name = 'publication-decade'
- class DecadeListFilterWithoutParameter(DecadeListFilter):
- title = 'publication decade'
- class DecadeListFilterWithNoneReturningLookups(DecadeListFilterWithTitleAndParameter):
- def lookups(self, request, model_admin):
- pass
- class DecadeListFilterWithFailingQueryset(DecadeListFilterWithTitleAndParameter):
- def queryset(self, request, queryset):
- raise 1 / 0
- class DecadeListFilterWithQuerysetBasedLookups(DecadeListFilterWithTitleAndParameter):
- def lookups(self, request, model_admin):
- qs = model_admin.get_queryset(request)
- if qs.filter(year__gte=1980, year__lte=1989).exists():
- yield ('the 80s', "the 1980's")
- if qs.filter(year__gte=1990, year__lte=1999).exists():
- yield ('the 90s', "the 1990's")
- if qs.filter(year__gte=2000, year__lte=2009).exists():
- yield ('the 00s', "the 2000's")
- class DecadeListFilterParameterEndsWith__In(DecadeListFilter):
- title = 'publication decade'
- parameter_name = 'decade__in' # Ends with '__in"
- class DecadeListFilterParameterEndsWith__Isnull(DecadeListFilter):
- title = 'publication decade'
- parameter_name = 'decade__isnull' # Ends with '__isnull"
- class DepartmentListFilterLookupWithNonStringValue(SimpleListFilter):
- title = 'department'
- parameter_name = 'department'
- def lookups(self, request, model_admin):
- return sorted({
- (employee.department.id, # Intentionally not a string (Refs #19318)
- employee.department.code)
- for employee in model_admin.get_queryset(request).all()
- })
- def queryset(self, request, queryset):
- if self.value():
- return queryset.filter(department__id=self.value())
- class DepartmentListFilterLookupWithUnderscoredParameter(DepartmentListFilterLookupWithNonStringValue):
- parameter_name = 'department__whatever'
- class DepartmentListFilterLookupWithDynamicValue(DecadeListFilterWithTitleAndParameter):
- def lookups(self, request, model_admin):
- if self.value() == 'the 80s':
- return (('the 90s', "the 1990's"),)
- elif self.value() == 'the 90s':
- return (('the 80s', "the 1980's"),)
- else:
- return (('the 80s', "the 1980's"), ('the 90s', "the 1990's"),)
- class CustomUserAdmin(UserAdmin):
- list_filter = ('books_authored', 'books_contributed')
- class BookAdmin(ModelAdmin):
- list_filter = ('year', 'author', 'contributors', 'is_best_seller', 'date_registered', 'no', 'availability')
- ordering = ('-id',)
- class BookAdminWithTupleBooleanFilter(BookAdmin):
- list_filter = (
- 'year',
- 'author',
- 'contributors',
- ('is_best_seller', BooleanFieldListFilter),
- 'date_registered',
- 'no',
- ('availability', BooleanFieldListFilter),
- )
- class BookAdminWithUnderscoreLookupAndTuple(BookAdmin):
- list_filter = (
- 'year',
- ('author__email', AllValuesFieldListFilter),
- 'contributors',
- 'is_best_seller',
- 'date_registered',
- 'no',
- )
- class BookAdminWithCustomQueryset(ModelAdmin):
- def __init__(self, user, *args, **kwargs):
- self.user = user
- super().__init__(*args, **kwargs)
- list_filter = ('year',)
- def get_queryset(self, request):
- return super().get_queryset(request).filter(author=self.user)
- class BookAdminRelatedOnlyFilter(ModelAdmin):
- list_filter = (
- 'year', 'is_best_seller', 'date_registered', 'no',
- ('author', RelatedOnlyFieldListFilter),
- ('contributors', RelatedOnlyFieldListFilter),
- ('employee__department', RelatedOnlyFieldListFilter),
- )
- ordering = ('-id',)
- class DecadeFilterBookAdmin(ModelAdmin):
- list_filter = ('author', DecadeListFilterWithTitleAndParameter)
- ordering = ('-id',)
- class NotNinetiesListFilterAdmin(ModelAdmin):
- list_filter = (NotNinetiesListFilter,)
- class DecadeFilterBookAdminWithoutTitle(ModelAdmin):
- list_filter = (DecadeListFilterWithoutTitle,)
- class DecadeFilterBookAdminWithoutParameter(ModelAdmin):
- list_filter = (DecadeListFilterWithoutParameter,)
- class DecadeFilterBookAdminWithNoneReturningLookups(ModelAdmin):
- list_filter = (DecadeListFilterWithNoneReturningLookups,)
- class DecadeFilterBookAdminWithFailingQueryset(ModelAdmin):
- list_filter = (DecadeListFilterWithFailingQueryset,)
- class DecadeFilterBookAdminWithQuerysetBasedLookups(ModelAdmin):
- list_filter = (DecadeListFilterWithQuerysetBasedLookups,)
- class DecadeFilterBookAdminParameterEndsWith__In(ModelAdmin):
- list_filter = (DecadeListFilterParameterEndsWith__In,)
- class DecadeFilterBookAdminParameterEndsWith__Isnull(ModelAdmin):
- list_filter = (DecadeListFilterParameterEndsWith__Isnull,)
- class EmployeeAdmin(ModelAdmin):
- list_display = ['name', 'department']
- list_filter = ['department']
- class DepartmentFilterEmployeeAdmin(EmployeeAdmin):
- list_filter = [DepartmentListFilterLookupWithNonStringValue]
- class DepartmentFilterUnderscoredEmployeeAdmin(EmployeeAdmin):
- list_filter = [DepartmentListFilterLookupWithUnderscoredParameter]
- class DepartmentFilterDynamicValueBookAdmin(EmployeeAdmin):
- list_filter = [DepartmentListFilterLookupWithDynamicValue]
- class BookmarkAdminGenericRelation(ModelAdmin):
- list_filter = ['tags__tag']
- class BookAdminWithEmptyFieldListFilter(ModelAdmin):
- list_filter = [
- ('author', EmptyFieldListFilter),
- ('title', EmptyFieldListFilter),
- ('improvedbook', EmptyFieldListFilter),
- ]
- class DepartmentAdminWithEmptyFieldListFilter(ModelAdmin):
- list_filter = [
- ('description', EmptyFieldListFilter),
- ('employee', EmptyFieldListFilter),
- ]
- class ListFiltersTests(TestCase):
- request_factory = RequestFactory()
- @classmethod
- def setUpTestData(cls):
- cls.today = datetime.date.today()
- cls.tomorrow = cls.today + datetime.timedelta(days=1)
- cls.one_week_ago = cls.today - datetime.timedelta(days=7)
- if cls.today.month == 12:
- cls.next_month = cls.today.replace(year=cls.today.year + 1, month=1, day=1)
- else:
- cls.next_month = cls.today.replace(month=cls.today.month + 1, day=1)
- cls.next_year = cls.today.replace(year=cls.today.year + 1, month=1, day=1)
- # Users
- cls.alfred = User.objects.create_superuser('alfred', 'alfred@example.com', 'password')
- cls.bob = User.objects.create_user('bob', 'bob@example.com')
- cls.lisa = User.objects.create_user('lisa', 'lisa@example.com')
- # Books
- cls.djangonaut_book = Book.objects.create(
- title='Djangonaut: an art of living', year=2009,
- author=cls.alfred, is_best_seller=True, date_registered=cls.today,
- availability=True,
- )
- cls.bio_book = Book.objects.create(
- title='Django: a biography', year=1999, author=cls.alfred,
- is_best_seller=False, no=207,
- availability=False,
- )
- cls.django_book = Book.objects.create(
- title='The Django Book', year=None, author=cls.bob,
- is_best_seller=None, date_registered=cls.today, no=103,
- availability=True,
- )
- cls.guitar_book = Book.objects.create(
- title='Guitar for dummies', year=2002, is_best_seller=True,
- date_registered=cls.one_week_ago,
- availability=None,
- )
- cls.guitar_book.contributors.set([cls.bob, cls.lisa])
- # Departments
- cls.dev = Department.objects.create(code='DEV', description='Development')
- cls.design = Department.objects.create(code='DSN', description='Design')
- # Employees
- cls.john = Employee.objects.create(name='John Blue', department=cls.dev)
- cls.jack = Employee.objects.create(name='Jack Red', department=cls.design)
- def test_choicesfieldlistfilter_has_none_choice(self):
- """
- The last choice is for the None value.
- """
- class BookmarkChoicesAdmin(ModelAdmin):
- list_display = ['none_or_null']
- list_filter = ['none_or_null']
- modeladmin = BookmarkChoicesAdmin(Bookmark, site)
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[-1]['display'], 'None')
- self.assertEqual(choices[-1]['query_string'], '?none_or_null__isnull=True')
- def test_datefieldlistfilter(self):
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist(request)
- request = self.request_factory.get('/', {
- 'date_registered__gte': self.today,
- 'date_registered__lt': self.tomorrow},
- )
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.django_book, self.djangonaut_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][4]
- self.assertEqual(filterspec.title, 'date registered')
- choice = select_by(filterspec.choices(changelist), "display", "Today")
- self.assertIs(choice['selected'], True)
- self.assertEqual(
- choice['query_string'],
- '?date_registered__gte=%s&date_registered__lt=%s' % (
- self.today,
- self.tomorrow,
- )
- )
- request = self.request_factory.get('/', {
- 'date_registered__gte': self.today.replace(day=1),
- 'date_registered__lt': self.next_month},
- )
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- if (self.today.year, self.today.month) == (self.one_week_ago.year, self.one_week_ago.month):
- # In case one week ago is in the same month.
- self.assertEqual(list(queryset), [self.guitar_book, self.django_book, self.djangonaut_book])
- else:
- self.assertEqual(list(queryset), [self.django_book, self.djangonaut_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][4]
- self.assertEqual(filterspec.title, 'date registered')
- choice = select_by(filterspec.choices(changelist), "display", "This month")
- self.assertIs(choice['selected'], True)
- self.assertEqual(
- choice['query_string'],
- '?date_registered__gte=%s&date_registered__lt=%s' % (
- self.today.replace(day=1),
- self.next_month,
- )
- )
- request = self.request_factory.get('/', {
- 'date_registered__gte': self.today.replace(month=1, day=1),
- 'date_registered__lt': self.next_year},
- )
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- if self.today.year == self.one_week_ago.year:
- # In case one week ago is in the same year.
- self.assertEqual(list(queryset), [self.guitar_book, self.django_book, self.djangonaut_book])
- else:
- self.assertEqual(list(queryset), [self.django_book, self.djangonaut_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][4]
- self.assertEqual(filterspec.title, 'date registered')
- choice = select_by(filterspec.choices(changelist), "display", "This year")
- self.assertIs(choice['selected'], True)
- self.assertEqual(
- choice['query_string'],
- '?date_registered__gte=%s&date_registered__lt=%s' % (
- self.today.replace(month=1, day=1),
- self.next_year,
- )
- )
- request = self.request_factory.get('/', {
- 'date_registered__gte': str(self.one_week_ago),
- 'date_registered__lt': str(self.tomorrow),
- })
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.guitar_book, self.django_book, self.djangonaut_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][4]
- self.assertEqual(filterspec.title, 'date registered')
- choice = select_by(filterspec.choices(changelist), "display", "Past 7 days")
- self.assertIs(choice['selected'], True)
- self.assertEqual(
- choice['query_string'],
- '?date_registered__gte=%s&date_registered__lt=%s' % (
- str(self.one_week_ago),
- str(self.tomorrow),
- )
- )
- # Null/not null queries
- request = self.request_factory.get('/', {'date_registered__isnull': 'True'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(queryset.count(), 1)
- self.assertEqual(queryset[0], self.bio_book)
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][4]
- self.assertEqual(filterspec.title, 'date registered')
- choice = select_by(filterspec.choices(changelist), 'display', 'No date')
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?date_registered__isnull=True')
- request = self.request_factory.get('/', {'date_registered__isnull': 'False'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(queryset.count(), 3)
- self.assertEqual(list(queryset), [self.guitar_book, self.django_book, self.djangonaut_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][4]
- self.assertEqual(filterspec.title, 'date registered')
- choice = select_by(filterspec.choices(changelist), 'display', 'Has date')
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?date_registered__isnull=False')
- @unittest.skipIf(
- sys.platform == 'win32',
- "Windows doesn't support setting a timezone that differs from the "
- "system timezone."
- )
- @override_settings(USE_TZ=True)
- def test_datefieldlistfilter_with_time_zone_support(self):
- # Regression for #17830
- self.test_datefieldlistfilter()
- def test_allvaluesfieldlistfilter(self):
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/', {'year__isnull': 'True'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.django_book])
- # Make sure the last choice is None and is selected
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'year')
- choices = list(filterspec.choices(changelist))
- self.assertIs(choices[-1]['selected'], True)
- self.assertEqual(choices[-1]['query_string'], '?year__isnull=True')
- request = self.request_factory.get('/', {'year': '2002'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'year')
- choices = list(filterspec.choices(changelist))
- self.assertIs(choices[2]['selected'], True)
- self.assertEqual(choices[2]['query_string'], '?year=2002')
- def test_allvaluesfieldlistfilter_custom_qs(self):
- # Make sure that correct filters are returned with custom querysets
- modeladmin = BookAdminWithCustomQueryset(self.alfred, Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- choices = list(filterspec.choices(changelist))
- # Should have 'All', 1999 and 2009 options i.e. the subset of years of
- # books written by alfred (which is the filtering criteria set by
- # BookAdminWithCustomQueryset.get_queryset())
- self.assertEqual(3, len(choices))
- self.assertEqual(choices[0]['query_string'], '?')
- self.assertEqual(choices[1]['query_string'], '?year=1999')
- self.assertEqual(choices[2]['query_string'], '?year=2009')
- def test_relatedfieldlistfilter_foreignkey(self):
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure that all users are present in the author's list filter
- filterspec = changelist.get_filters(request)[0][1]
- expected = [(self.alfred.pk, 'alfred'), (self.bob.pk, 'bob'), (self.lisa.pk, 'lisa')]
- self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
- request = self.request_factory.get('/', {'author__isnull': 'True'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.guitar_book])
- # Make sure the last choice is None and is selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'Verbose Author')
- choices = list(filterspec.choices(changelist))
- self.assertIs(choices[-1]['selected'], True)
- self.assertEqual(choices[-1]['query_string'], '?author__isnull=True')
- request = self.request_factory.get('/', {'author__id__exact': self.alfred.pk})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'Verbose Author')
- # order of choices depends on User model, which has no order
- choice = select_by(filterspec.choices(changelist), "display", "alfred")
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?author__id__exact=%d' % self.alfred.pk)
- def test_relatedfieldlistfilter_foreignkey_ordering(self):
- """RelatedFieldListFilter ordering respects ModelAdmin.ordering."""
- class EmployeeAdminWithOrdering(ModelAdmin):
- ordering = ('name',)
- class BookAdmin(ModelAdmin):
- list_filter = ('employee',)
- site.register(Employee, EmployeeAdminWithOrdering)
- self.addCleanup(lambda: site.unregister(Employee))
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- expected = [(self.jack.pk, 'Jack Red'), (self.john.pk, 'John Blue')]
- self.assertEqual(filterspec.lookup_choices, expected)
- def test_relatedfieldlistfilter_foreignkey_ordering_reverse(self):
- class EmployeeAdminWithOrdering(ModelAdmin):
- ordering = ('-name',)
- class BookAdmin(ModelAdmin):
- list_filter = ('employee',)
- site.register(Employee, EmployeeAdminWithOrdering)
- self.addCleanup(lambda: site.unregister(Employee))
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- expected = [(self.john.pk, 'John Blue'), (self.jack.pk, 'Jack Red')]
- self.assertEqual(filterspec.lookup_choices, expected)
- def test_relatedfieldlistfilter_foreignkey_default_ordering(self):
- """RelatedFieldListFilter ordering respects Model.ordering."""
- class BookAdmin(ModelAdmin):
- list_filter = ('employee',)
- self.addCleanup(setattr, Employee._meta, 'ordering', Employee._meta.ordering)
- Employee._meta.ordering = ('name',)
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- expected = [(self.jack.pk, 'Jack Red'), (self.john.pk, 'John Blue')]
- self.assertEqual(filterspec.lookup_choices, expected)
- def test_relatedfieldlistfilter_manytomany(self):
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure that all users are present in the contrib's list filter
- filterspec = changelist.get_filters(request)[0][2]
- expected = [(self.alfred.pk, 'alfred'), (self.bob.pk, 'bob'), (self.lisa.pk, 'lisa')]
- self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
- request = self.request_factory.get('/', {'contributors__isnull': 'True'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.django_book, self.bio_book, self.djangonaut_book])
- # Make sure the last choice is None and is selected
- filterspec = changelist.get_filters(request)[0][2]
- self.assertEqual(filterspec.title, 'Verbose Contributors')
- choices = list(filterspec.choices(changelist))
- self.assertIs(choices[-1]['selected'], True)
- self.assertEqual(choices[-1]['query_string'], '?contributors__isnull=True')
- request = self.request_factory.get('/', {'contributors__id__exact': self.bob.pk})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][2]
- self.assertEqual(filterspec.title, 'Verbose Contributors')
- choice = select_by(filterspec.choices(changelist), "display", "bob")
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?contributors__id__exact=%d' % self.bob.pk)
- def test_relatedfieldlistfilter_reverse_relationships(self):
- modeladmin = CustomUserAdmin(User, site)
- # FK relationship -----
- request = self.request_factory.get('/', {'books_authored__isnull': 'True'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.lisa])
- # Make sure the last choice is None and is selected
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'book')
- choices = list(filterspec.choices(changelist))
- self.assertIs(choices[-1]['selected'], True)
- self.assertEqual(choices[-1]['query_string'], '?books_authored__isnull=True')
- request = self.request_factory.get('/', {'books_authored__id__exact': self.bio_book.pk})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'book')
- choice = select_by(filterspec.choices(changelist), "display", self.bio_book.title)
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?books_authored__id__exact=%d' % self.bio_book.pk)
- # M2M relationship -----
- request = self.request_factory.get('/', {'books_contributed__isnull': 'True'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.alfred])
- # Make sure the last choice is None and is selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'book')
- choices = list(filterspec.choices(changelist))
- self.assertIs(choices[-1]['selected'], True)
- self.assertEqual(choices[-1]['query_string'], '?books_contributed__isnull=True')
- request = self.request_factory.get('/', {'books_contributed__id__exact': self.django_book.pk})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'book')
- choice = select_by(filterspec.choices(changelist), "display", self.django_book.title)
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?books_contributed__id__exact=%d' % self.django_book.pk)
- # With one book, the list filter should appear because there is also a
- # (None) option.
- Book.objects.exclude(pk=self.djangonaut_book.pk).delete()
- filterspec = changelist.get_filters(request)[0]
- self.assertEqual(len(filterspec), 2)
- # With no books remaining, no list filters should appear.
- Book.objects.all().delete()
- filterspec = changelist.get_filters(request)[0]
- self.assertEqual(len(filterspec), 0)
- def test_relatedfieldlistfilter_reverse_relationships_default_ordering(self):
- self.addCleanup(setattr, Book._meta, 'ordering', Book._meta.ordering)
- Book._meta.ordering = ('title',)
- modeladmin = CustomUserAdmin(User, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- expected = [
- (self.bio_book.pk, 'Django: a biography'),
- (self.djangonaut_book.pk, 'Djangonaut: an art of living'),
- (self.guitar_book.pk, 'Guitar for dummies'),
- (self.django_book.pk, 'The Django Book')
- ]
- self.assertEqual(filterspec.lookup_choices, expected)
- def test_relatedonlyfieldlistfilter_foreignkey(self):
- modeladmin = BookAdminRelatedOnlyFilter(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure that only actual authors are present in author's list filter
- filterspec = changelist.get_filters(request)[0][4]
- expected = [(self.alfred.pk, 'alfred'), (self.bob.pk, 'bob')]
- self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
- def test_relatedonlyfieldlistfilter_foreignkey_reverse_relationships(self):
- class EmployeeAdminReverseRelationship(ModelAdmin):
- list_filter = (
- ('book', RelatedOnlyFieldListFilter),
- )
- self.djangonaut_book.employee = self.john
- self.djangonaut_book.save()
- self.django_book.employee = self.jack
- self.django_book.save()
- modeladmin = EmployeeAdminReverseRelationship(Employee, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.lookup_choices, [
- (self.djangonaut_book.pk, 'Djangonaut: an art of living'),
- (self.django_book.pk, 'The Django Book'),
- ])
- def test_relatedonlyfieldlistfilter_manytomany_reverse_relationships(self):
- class UserAdminReverseRelationship(ModelAdmin):
- list_filter = (
- ('books_contributed', RelatedOnlyFieldListFilter),
- )
- modeladmin = UserAdminReverseRelationship(User, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(
- filterspec.lookup_choices,
- [(self.guitar_book.pk, 'Guitar for dummies')],
- )
- def test_relatedonlyfieldlistfilter_foreignkey_ordering(self):
- """RelatedOnlyFieldListFilter ordering respects ModelAdmin.ordering."""
- class EmployeeAdminWithOrdering(ModelAdmin):
- ordering = ('name',)
- class BookAdmin(ModelAdmin):
- list_filter = (
- ('employee', RelatedOnlyFieldListFilter),
- )
- albert = Employee.objects.create(name='Albert Green', department=self.dev)
- self.djangonaut_book.employee = albert
- self.djangonaut_book.save()
- self.bio_book.employee = self.jack
- self.bio_book.save()
- site.register(Employee, EmployeeAdminWithOrdering)
- self.addCleanup(lambda: site.unregister(Employee))
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- expected = [(albert.pk, 'Albert Green'), (self.jack.pk, 'Jack Red')]
- self.assertEqual(filterspec.lookup_choices, expected)
- def test_relatedonlyfieldlistfilter_foreignkey_default_ordering(self):
- """RelatedOnlyFieldListFilter ordering respects Meta.ordering."""
- class BookAdmin(ModelAdmin):
- list_filter = (
- ('employee', RelatedOnlyFieldListFilter),
- )
- albert = Employee.objects.create(name='Albert Green', department=self.dev)
- self.djangonaut_book.employee = albert
- self.djangonaut_book.save()
- self.bio_book.employee = self.jack
- self.bio_book.save()
- self.addCleanup(setattr, Employee._meta, 'ordering', Employee._meta.ordering)
- Employee._meta.ordering = ('name',)
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- expected = [(albert.pk, 'Albert Green'), (self.jack.pk, 'Jack Red')]
- self.assertEqual(filterspec.lookup_choices, expected)
- def test_relatedonlyfieldlistfilter_underscorelookup_foreignkey(self):
- Department.objects.create(code='TEST', description='Testing')
- self.djangonaut_book.employee = self.john
- self.djangonaut_book.save()
- self.bio_book.employee = self.jack
- self.bio_book.save()
- modeladmin = BookAdminRelatedOnlyFilter(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Only actual departments should be present in employee__department's
- # list filter.
- filterspec = changelist.get_filters(request)[0][6]
- expected = [
- (self.dev.code, str(self.dev)),
- (self.design.code, str(self.design)),
- ]
- self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
- def test_relatedonlyfieldlistfilter_manytomany(self):
- modeladmin = BookAdminRelatedOnlyFilter(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure that only actual contributors are present in contrib's list filter
- filterspec = changelist.get_filters(request)[0][5]
- expected = [(self.bob.pk, 'bob'), (self.lisa.pk, 'lisa')]
- self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
- def test_listfilter_genericrelation(self):
- django_bookmark = Bookmark.objects.create(url='https://www.djangoproject.com/')
- python_bookmark = Bookmark.objects.create(url='https://www.python.org/')
- kernel_bookmark = Bookmark.objects.create(url='https://www.kernel.org/')
- TaggedItem.objects.create(content_object=django_bookmark, tag='python')
- TaggedItem.objects.create(content_object=python_bookmark, tag='python')
- TaggedItem.objects.create(content_object=kernel_bookmark, tag='linux')
- modeladmin = BookmarkAdminGenericRelation(Bookmark, site)
- request = self.request_factory.get('/', {'tags__tag': 'python'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- expected = [python_bookmark, django_bookmark]
- self.assertEqual(list(queryset), expected)
- def test_booleanfieldlistfilter(self):
- modeladmin = BookAdmin(Book, site)
- self.verify_booleanfieldlistfilter(modeladmin)
- def test_booleanfieldlistfilter_tuple(self):
- modeladmin = BookAdminWithTupleBooleanFilter(Book, site)
- self.verify_booleanfieldlistfilter(modeladmin)
- def verify_booleanfieldlistfilter(self, modeladmin):
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- request = self.request_factory.get('/', {'is_best_seller__exact': 0})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.bio_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][3]
- self.assertEqual(filterspec.title, 'is best seller')
- choice = select_by(filterspec.choices(changelist), "display", "No")
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?is_best_seller__exact=0')
- request = self.request_factory.get('/', {'is_best_seller__exact': 1})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.guitar_book, self.djangonaut_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][3]
- self.assertEqual(filterspec.title, 'is best seller')
- choice = select_by(filterspec.choices(changelist), "display", "Yes")
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?is_best_seller__exact=1')
- request = self.request_factory.get('/', {'is_best_seller__isnull': 'True'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.django_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][3]
- self.assertEqual(filterspec.title, 'is best seller')
- choice = select_by(filterspec.choices(changelist), "display", "Unknown")
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?is_best_seller__isnull=True')
- def test_booleanfieldlistfilter_choices(self):
- modeladmin = BookAdmin(Book, site)
- self.verify_booleanfieldlistfilter_choices(modeladmin)
- def test_booleanfieldlistfilter_tuple_choices(self):
- modeladmin = BookAdminWithTupleBooleanFilter(Book, site)
- self.verify_booleanfieldlistfilter_choices(modeladmin)
- def verify_booleanfieldlistfilter_choices(self, modeladmin):
- # False.
- request = self.request_factory.get('/', {'availability__exact': 0})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.bio_book])
- filterspec = changelist.get_filters(request)[0][6]
- self.assertEqual(filterspec.title, 'availability')
- choice = select_by(filterspec.choices(changelist), 'display', 'Paid')
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?availability__exact=0')
- # True.
- request = self.request_factory.get('/', {'availability__exact': 1})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.django_book, self.djangonaut_book])
- filterspec = changelist.get_filters(request)[0][6]
- self.assertEqual(filterspec.title, 'availability')
- choice = select_by(filterspec.choices(changelist), 'display', 'Free')
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?availability__exact=1')
- # None.
- request = self.request_factory.get('/', {'availability__isnull': 'True'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.guitar_book])
- filterspec = changelist.get_filters(request)[0][6]
- self.assertEqual(filterspec.title, 'availability')
- choice = select_by(filterspec.choices(changelist), 'display', 'Obscure')
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?availability__isnull=True')
- # All.
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertEqual(
- list(queryset),
- [self.guitar_book, self.django_book, self.bio_book, self.djangonaut_book],
- )
- filterspec = changelist.get_filters(request)[0][6]
- self.assertEqual(filterspec.title, 'availability')
- choice = select_by(filterspec.choices(changelist), 'display', 'All')
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?')
- def test_fieldlistfilter_underscorelookup_tuple(self):
- """
- Ensure ('fieldpath', ClassName ) lookups pass lookup_allowed checks
- when fieldpath contains double underscore in value (#19182).
- """
- modeladmin = BookAdminWithUnderscoreLookupAndTuple(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- request = self.request_factory.get('/', {'author__email': 'alfred@example.com'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.bio_book, self.djangonaut_book])
- def test_fieldlistfilter_invalid_lookup_parameters(self):
- """Filtering by an invalid value."""
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/', {'author__id__exact': 'StringNotInteger!'})
- request.user = self.alfred
- with self.assertRaises(IncorrectLookupParameters):
- modeladmin.get_changelist_instance(request)
- def test_simplelistfilter(self):
- modeladmin = DecadeFilterBookAdmin(Book, site)
- # Make sure that the first option is 'All' ---------------------------
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), list(Book.objects.all().order_by('-id')))
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[0]['display'], 'All')
- self.assertIs(choices[0]['selected'], True)
- self.assertEqual(choices[0]['query_string'], '?')
- # Look for books in the 1980s ----------------------------------------
- request = self.request_factory.get('/', {'publication-decade': 'the 80s'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[1]['display'], 'the 1980\'s')
- self.assertIs(choices[1]['selected'], True)
- self.assertEqual(choices[1]['query_string'], '?publication-decade=the+80s')
- # Look for books in the 1990s ----------------------------------------
- request = self.request_factory.get('/', {'publication-decade': 'the 90s'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.bio_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[2]['display'], 'the 1990\'s')
- self.assertIs(choices[2]['selected'], True)
- self.assertEqual(choices[2]['query_string'], '?publication-decade=the+90s')
- # Look for books in the 2000s ----------------------------------------
- request = self.request_factory.get('/', {'publication-decade': 'the 00s'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.guitar_book, self.djangonaut_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[3]['display'], 'the 2000\'s')
- self.assertIs(choices[3]['selected'], True)
- self.assertEqual(choices[3]['query_string'], '?publication-decade=the+00s')
- # Combine multiple filters -------------------------------------------
- request = self.request_factory.get('/', {'publication-decade': 'the 00s', 'author__id__exact': self.alfred.pk})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.djangonaut_book])
- # Make sure the correct choices are selected
- filterspec = changelist.get_filters(request)[0][1]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[3]['display'], 'the 2000\'s')
- self.assertIs(choices[3]['selected'], True)
- self.assertEqual(
- choices[3]['query_string'],
- '?author__id__exact=%s&publication-decade=the+00s' % self.alfred.pk
- )
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'Verbose Author')
- choice = select_by(filterspec.choices(changelist), "display", "alfred")
- self.assertIs(choice['selected'], True)
- self.assertEqual(choice['query_string'], '?author__id__exact=%s&publication-decade=the+00s' % self.alfred.pk)
- def test_listfilter_without_title(self):
- """
- Any filter must define a title.
- """
- modeladmin = DecadeFilterBookAdminWithoutTitle(Book, site)
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- msg = "The list filter 'DecadeListFilterWithoutTitle' does not specify a 'title'."
- with self.assertRaisesMessage(ImproperlyConfigured, msg):
- modeladmin.get_changelist_instance(request)
- def test_simplelistfilter_without_parameter(self):
- """
- Any SimpleListFilter must define a parameter_name.
- """
- modeladmin = DecadeFilterBookAdminWithoutParameter(Book, site)
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- msg = "The list filter 'DecadeListFilterWithoutParameter' does not specify a 'parameter_name'."
- with self.assertRaisesMessage(ImproperlyConfigured, msg):
- modeladmin.get_changelist_instance(request)
- def test_simplelistfilter_with_none_returning_lookups(self):
- """
- A SimpleListFilter lookups method can return None but disables the
- filter completely.
- """
- modeladmin = DecadeFilterBookAdminWithNoneReturningLookups(Book, site)
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0]
- self.assertEqual(len(filterspec), 0)
- def test_filter_with_failing_queryset(self):
- """
- When a filter's queryset method fails, it fails loudly and
- the corresponding exception doesn't get swallowed (#17828).
- """
- modeladmin = DecadeFilterBookAdminWithFailingQueryset(Book, site)
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- with self.assertRaises(ZeroDivisionError):
- modeladmin.get_changelist_instance(request)
- def test_simplelistfilter_with_queryset_based_lookups(self):
- modeladmin = DecadeFilterBookAdminWithQuerysetBasedLookups(Book, site)
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(len(choices), 3)
- self.assertEqual(choices[0]['display'], 'All')
- self.assertIs(choices[0]['selected'], True)
- self.assertEqual(choices[0]['query_string'], '?')
- self.assertEqual(choices[1]['display'], 'the 1990\'s')
- self.assertIs(choices[1]['selected'], False)
- self.assertEqual(choices[1]['query_string'], '?publication-decade=the+90s')
- self.assertEqual(choices[2]['display'], 'the 2000\'s')
- self.assertIs(choices[2]['selected'], False)
- self.assertEqual(choices[2]['query_string'], '?publication-decade=the+00s')
- def test_two_characters_long_field(self):
- """
- list_filter works with two-characters long field names (#16080).
- """
- modeladmin = BookAdmin(Book, site)
- request = self.request_factory.get('/', {'no': '207'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.bio_book])
- filterspec = changelist.get_filters(request)[0][5]
- self.assertEqual(filterspec.title, 'number')
- choices = list(filterspec.choices(changelist))
- self.assertIs(choices[2]['selected'], True)
- self.assertEqual(choices[2]['query_string'], '?no=207')
- def test_parameter_ends_with__in__or__isnull(self):
- """
- A SimpleListFilter's parameter name is not mistaken for a model field
- if it ends with '__isnull' or '__in' (#17091).
- """
- # When it ends with '__in' -----------------------------------------
- modeladmin = DecadeFilterBookAdminParameterEndsWith__In(Book, site)
- request = self.request_factory.get('/', {'decade__in': 'the 90s'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.bio_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[2]['display'], 'the 1990\'s')
- self.assertIs(choices[2]['selected'], True)
- self.assertEqual(choices[2]['query_string'], '?decade__in=the+90s')
- # When it ends with '__isnull' ---------------------------------------
- modeladmin = DecadeFilterBookAdminParameterEndsWith__Isnull(Book, site)
- request = self.request_factory.get('/', {'decade__isnull': 'the 90s'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.bio_book])
- # Make sure the correct choice is selected
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[2]['display'], 'the 1990\'s')
- self.assertIs(choices[2]['selected'], True)
- self.assertEqual(choices[2]['query_string'], '?decade__isnull=the+90s')
- def test_lookup_with_non_string_value(self):
- """
- Ensure choices are set the selected class when using non-string values
- for lookups in SimpleListFilters (#19318).
- """
- modeladmin = DepartmentFilterEmployeeAdmin(Employee, site)
- request = self.request_factory.get('/', {'department': self.john.department.pk})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.john])
- filterspec = changelist.get_filters(request)[0][-1]
- self.assertEqual(filterspec.title, 'department')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[1]['display'], 'DEV')
- self.assertIs(choices[1]['selected'], True)
- self.assertEqual(choices[1]['query_string'], '?department=%s' % self.john.department.pk)
- def test_lookup_with_non_string_value_underscored(self):
- """
- Ensure SimpleListFilter lookups pass lookup_allowed checks when
- parameter_name attribute contains double-underscore value (#19182).
- """
- modeladmin = DepartmentFilterUnderscoredEmployeeAdmin(Employee, site)
- request = self.request_factory.get('/', {'department__whatever': self.john.department.pk})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.john])
- filterspec = changelist.get_filters(request)[0][-1]
- self.assertEqual(filterspec.title, 'department')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[1]['display'], 'DEV')
- self.assertIs(choices[1]['selected'], True)
- self.assertEqual(choices[1]['query_string'], '?department__whatever=%s' % self.john.department.pk)
- def test_fk_with_to_field(self):
- """
- A filter on a FK respects the FK's to_field attribute (#17972).
- """
- modeladmin = EmployeeAdmin(Employee, site)
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.jack, self.john])
- filterspec = changelist.get_filters(request)[0][-1]
- self.assertEqual(filterspec.title, 'department')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[0]['display'], 'All')
- self.assertIs(choices[0]['selected'], True)
- self.assertEqual(choices[0]['query_string'], '?')
- self.assertEqual(choices[1]['display'], 'Development')
- self.assertIs(choices[1]['selected'], False)
- self.assertEqual(choices[1]['query_string'], '?department__code__exact=DEV')
- self.assertEqual(choices[2]['display'], 'Design')
- self.assertIs(choices[2]['selected'], False)
- self.assertEqual(choices[2]['query_string'], '?department__code__exact=DSN')
- # Filter by Department=='Development' --------------------------------
- request = self.request_factory.get('/', {'department__code__exact': 'DEV'})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- # Make sure the correct queryset is returned
- queryset = changelist.get_queryset(request)
- self.assertEqual(list(queryset), [self.john])
- filterspec = changelist.get_filters(request)[0][-1]
- self.assertEqual(filterspec.title, 'department')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(choices[0]['display'], 'All')
- self.assertIs(choices[0]['selected'], False)
- self.assertEqual(choices[0]['query_string'], '?')
- self.assertEqual(choices[1]['display'], 'Development')
- self.assertIs(choices[1]['selected'], True)
- self.assertEqual(choices[1]['query_string'], '?department__code__exact=DEV')
- self.assertEqual(choices[2]['display'], 'Design')
- self.assertIs(choices[2]['selected'], False)
- self.assertEqual(choices[2]['query_string'], '?department__code__exact=DSN')
- def test_lookup_with_dynamic_value(self):
- """
- Ensure SimpleListFilter can access self.value() inside the lookup.
- """
- modeladmin = DepartmentFilterDynamicValueBookAdmin(Book, site)
- def _test_choices(request, expected_displays):
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'publication decade')
- choices = tuple(c['display'] for c in filterspec.choices(changelist))
- self.assertEqual(choices, expected_displays)
- _test_choices(self.request_factory.get('/', {}),
- ("All", "the 1980's", "the 1990's"))
- _test_choices(self.request_factory.get('/', {'publication-decade': 'the 80s'}),
- ("All", "the 1990's"))
- _test_choices(self.request_factory.get('/', {'publication-decade': 'the 90s'}),
- ("All", "the 1980's"))
- def test_list_filter_queryset_filtered_by_default(self):
- """
- A list filter that filters the queryset by default gives the correct
- full_result_count.
- """
- modeladmin = NotNinetiesListFilterAdmin(Book, site)
- request = self.request_factory.get('/', {})
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- changelist.get_results(request)
- self.assertEqual(changelist.full_result_count, 4)
- def test_emptylistfieldfilter(self):
- empty_description = Department.objects.create(code='EMPT', description='')
- none_description = Department.objects.create(code='NONE', description=None)
- empty_title = Book.objects.create(title='', author=self.alfred)
- department_admin = DepartmentAdminWithEmptyFieldListFilter(Department, site)
- book_admin = BookAdminWithEmptyFieldListFilter(Book, site)
- tests = [
- # Allows nulls and empty strings.
- (
- department_admin,
- {'description__isempty': '1'},
- [empty_description, none_description],
- ),
- (
- department_admin,
- {'description__isempty': '0'},
- [self.dev, self.design],
- ),
- # Allows nulls.
- (book_admin, {'author__isempty': '1'}, [self.guitar_book]),
- (
- book_admin,
- {'author__isempty': '0'},
- [self.django_book, self.bio_book, self.djangonaut_book, empty_title],
- ),
- # Allows empty strings.
- (book_admin, {'title__isempty': '1'}, [empty_title]),
- (
- book_admin,
- {'title__isempty': '0'},
- [self.django_book, self.bio_book, self.djangonaut_book, self.guitar_book],
- ),
- ]
- for modeladmin, query_string, expected_result in tests:
- with self.subTest(
- modeladmin=modeladmin.__class__.__name__,
- query_string=query_string,
- ):
- request = self.request_factory.get('/', query_string)
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertCountEqual(queryset, expected_result)
- def test_emptylistfieldfilter_reverse_relationships(self):
- class UserAdminReverseRelationship(UserAdmin):
- list_filter = (
- ('books_contributed', EmptyFieldListFilter),
- )
- ImprovedBook.objects.create(book=self.guitar_book)
- no_employees = Department.objects.create(code='NONE', description=None)
- book_admin = BookAdminWithEmptyFieldListFilter(Book, site)
- department_admin = DepartmentAdminWithEmptyFieldListFilter(Department, site)
- user_admin = UserAdminReverseRelationship(User, site)
- tests = [
- # Reverse one-to-one relationship.
- (
- book_admin,
- {'improvedbook__isempty': '1'},
- [self.django_book, self.bio_book, self.djangonaut_book],
- ),
- (book_admin, {'improvedbook__isempty': '0'}, [self.guitar_book]),
- # Reverse foreign key relationship.
- (department_admin, {'employee__isempty': '1'}, [no_employees]),
- (department_admin, {'employee__isempty': '0'}, [self.dev, self.design]),
- # Reverse many-to-many relationship.
- (user_admin, {'books_contributed__isempty': '1'}, [self.alfred]),
- (user_admin, {'books_contributed__isempty': '0'}, [self.bob, self.lisa]),
- ]
- for modeladmin, query_string, expected_result in tests:
- with self.subTest(
- modeladmin=modeladmin.__class__.__name__,
- query_string=query_string,
- ):
- request = self.request_factory.get('/', query_string)
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertCountEqual(queryset, expected_result)
- def test_emptylistfieldfilter_genericrelation(self):
- class BookmarkGenericRelation(ModelAdmin):
- list_filter = (
- ('tags', EmptyFieldListFilter),
- )
- modeladmin = BookmarkGenericRelation(Bookmark, site)
- django_bookmark = Bookmark.objects.create(url='https://www.djangoproject.com/')
- python_bookmark = Bookmark.objects.create(url='https://www.python.org/')
- none_tags = Bookmark.objects.create(url='https://www.kernel.org/')
- TaggedItem.objects.create(content_object=django_bookmark, tag='python')
- TaggedItem.objects.create(content_object=python_bookmark, tag='python')
- tests = [
- ({'tags__isempty': '1'}, [none_tags]),
- ({'tags__isempty': '0'}, [django_bookmark, python_bookmark]),
- ]
- for query_string, expected_result in tests:
- with self.subTest(query_string=query_string):
- request = self.request_factory.get('/', query_string)
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- queryset = changelist.get_queryset(request)
- self.assertCountEqual(queryset, expected_result)
- def test_emptylistfieldfilter_choices(self):
- modeladmin = BookAdminWithEmptyFieldListFilter(Book, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- changelist = modeladmin.get_changelist_instance(request)
- filterspec = changelist.get_filters(request)[0][0]
- self.assertEqual(filterspec.title, 'Verbose Author')
- choices = list(filterspec.choices(changelist))
- self.assertEqual(len(choices), 3)
- self.assertEqual(choices[0]['display'], 'All')
- self.assertIs(choices[0]['selected'], True)
- self.assertEqual(choices[0]['query_string'], '?')
- self.assertEqual(choices[1]['display'], 'Empty')
- self.assertIs(choices[1]['selected'], False)
- self.assertEqual(choices[1]['query_string'], '?author__isempty=1')
- self.assertEqual(choices[2]['display'], 'Not empty')
- self.assertIs(choices[2]['selected'], False)
- self.assertEqual(choices[2]['query_string'], '?author__isempty=0')
- def test_emptylistfieldfilter_non_empty_field(self):
- class EmployeeAdminWithEmptyFieldListFilter(ModelAdmin):
- list_filter = [('department', EmptyFieldListFilter)]
- modeladmin = EmployeeAdminWithEmptyFieldListFilter(Employee, site)
- request = self.request_factory.get('/')
- request.user = self.alfred
- msg = (
- "The list filter 'EmptyFieldListFilter' cannot be used with field "
- "'department' which doesn't allow empty strings and nulls."
- )
- with self.assertRaisesMessage(ImproperlyConfigured, msg):
- modeladmin.get_changelist_instance(request)
- def test_emptylistfieldfilter_invalid_lookup_parameters(self):
- modeladmin = BookAdminWithEmptyFieldListFilter(Book, site)
- request = self.request_factory.get('/', {'author__isempty': 42})
- request.user = self.alfred
- with self.assertRaises(IncorrectLookupParameters):
- modeladmin.get_changelist_instance(request)
|