1import contextlib
2import datetime
3import unittest
4from operator import attrgetter
5from unittest import mock
6
7from django import forms
8from django.http import QueryDict
9from django.test import TestCase, override_settings
10from django.utils import timezone
11from django.utils.timezone import make_aware, now
12
13from django_filters.filters import (
14    AllValuesFilter,
15    AllValuesMultipleFilter,
16    CharFilter,
17    ChoiceFilter,
18    DateFromToRangeFilter,
19    DateRangeFilter,
20    DateTimeFromToRangeFilter,
21    DurationFilter,
22    IsoDateTimeFromToRangeFilter,
23    LookupChoiceFilter,
24    ModelChoiceFilter,
25    ModelMultipleChoiceFilter,
26    MultipleChoiceFilter,
27    OrderingFilter,
28    RangeFilter,
29    TimeRangeFilter,
30    TypedMultipleChoiceFilter
31)
32from django_filters.filterset import FilterSet
33
34from .models import (
35    STATUS_CHOICES,
36    Account,
37    Article,
38    BankAccount,
39    Book,
40    Comment,
41    Company,
42    DirectedNode,
43    Location,
44    Node,
45    Profile,
46    SpacewalkRecord,
47    User
48)
49from .utils import MockQuerySet
50
51
52class CharFilterTests(TestCase):
53
54    def test_filtering(self):
55        b1 = Book.objects.create(
56            title="Ender's Game", price='1.00', average_rating=3.0)
57        b2 = Book.objects.create(
58            title="Rainbow Six", price='1.00', average_rating=3.0)
59        b3 = Book.objects.create(
60            title="Snowcrash", price='1.00', average_rating=3.0)
61
62        class F(FilterSet):
63            class Meta:
64                model = Book
65                fields = ['title']
66
67        qs = Book.objects.all()
68        f = F(queryset=qs)
69        self.assertQuerysetEqual(f.qs, [b1.pk, b2.pk, b3.pk],
70                                 lambda o: o.pk, ordered=False)
71        f = F({'title': 'Snowcrash'}, queryset=qs)
72        self.assertQuerysetEqual(f.qs, [b3.pk], lambda o: o.pk)
73
74
75class IntegerFilterTest(TestCase):
76
77    def test_filtering(self):
78        default_values = {
79            'in_good_standing': True,
80            'friendly': False,
81        }
82        b1 = BankAccount.objects.create(amount_saved=0, **default_values)
83        b2 = BankAccount.objects.create(amount_saved=3, **default_values)
84        b3 = BankAccount.objects.create(amount_saved=10, **default_values)
85
86        class F(FilterSet):
87            class Meta:
88                model = BankAccount
89                fields = ['amount_saved']
90
91        qs = BankAccount.objects.all()
92        f = F(queryset=qs)
93        self.assertQuerysetEqual(f.qs, [b1.pk, b2.pk, b3.pk],
94                                 lambda o: o.pk, ordered=False)
95        f = F({'amount_saved': '10'}, queryset=qs)
96        self.assertQuerysetEqual(f.qs, [b3.pk], lambda o: o.pk)
97        f = F({'amount_saved': '0'}, queryset=qs)
98        self.assertQuerysetEqual(f.qs, [b1.pk], lambda o: o.pk)
99
100
101class BooleanFilterTests(TestCase):
102
103    def test_filtering(self):
104        User.objects.create(username='alex', is_active=False)
105        User.objects.create(username='jacob', is_active=True)
106        User.objects.create(username='aaron', is_active=False)
107
108        class F(FilterSet):
109            class Meta:
110                model = User
111                fields = ['is_active']
112
113        qs = User.objects.all()
114
115        # '2' and '3' are how the field expects the data from the browser
116        f = F({'is_active': '2'}, queryset=qs)
117        self.assertQuerysetEqual(f.qs, ['jacob'], lambda o: o.username, False)
118
119        f = F({'is_active': '3'}, queryset=qs)
120        self.assertQuerysetEqual(f.qs,
121                                 ['alex', 'aaron'],
122                                 lambda o: o.username, False)
123
124        f = F({'is_active': '1'}, queryset=qs)
125        self.assertQuerysetEqual(f.qs,
126                                 ['alex', 'aaron', 'jacob'],
127                                 lambda o: o.username, False)
128
129
130class ChoiceFilterTests(TestCase):
131
132    @classmethod
133    def setUpTestData(cls):
134        User.objects.create(username='alex', status=1)
135        User.objects.create(username='jacob', status=2)
136        User.objects.create(username='aaron', status=2)
137        User.objects.create(username='carl', status=0)
138
139        Article.objects.create(author_id=1, published=now())
140        Article.objects.create(author_id=2, published=now())
141        Article.objects.create(author_id=3, published=now())
142        Article.objects.create(author_id=4, published=now())
143        Article.objects.create(author_id=None, published=now())
144
145    def test_filtering(self):
146        class F(FilterSet):
147            class Meta:
148                model = User
149                fields = ['status']
150
151        f = F()
152        self.assertQuerysetEqual(f.qs,
153                                 ['aaron', 'alex', 'jacob', 'carl'],
154                                 lambda o: o.username, False)
155        f = F({'status': '1'})
156        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username, False)
157
158        f = F({'status': '2'})
159        self.assertQuerysetEqual(f.qs, ['jacob', 'aaron'],
160                                 lambda o: o.username, False)
161
162        f = F({'status': '0'})
163        self.assertQuerysetEqual(f.qs, ['carl'], lambda o: o.username, False)
164
165    def test_filtering_on_explicitly_defined_field(self):
166        """
167        Test for #30.
168
169        If you explicitly declare ChoiceFilter fields you **MUST** pass `choices`.
170        """
171        class F(FilterSet):
172            status = ChoiceFilter(choices=STATUS_CHOICES)
173
174            class Meta:
175                model = User
176                fields = ['status']
177
178        f = F()
179        self.assertQuerysetEqual(f.qs,
180                                 ['aaron', 'alex', 'jacob', 'carl'],
181                                 lambda o: o.username, False)
182        f = F({'status': '1'})
183        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username, False)
184
185        f = F({'status': '2'})
186        self.assertQuerysetEqual(f.qs, ['jacob', 'aaron'],
187                                 lambda o: o.username, False)
188
189        f = F({'status': '0'})
190        self.assertQuerysetEqual(f.qs, ['carl'], lambda o: o.username, False)
191
192    def test_filtering_on_empty_choice(self):
193        class F(FilterSet):
194            class Meta:
195                model = User
196                fields = ['status']
197
198        f = F({'status': ''})
199        self.assertQuerysetEqual(f.qs,
200                                 ['aaron', 'alex', 'jacob', 'carl'],
201                                 lambda o: o.username, False)
202
203    def test_filtering_on_null_choice(self):
204        choices = [(u.pk, str(u)) for u in User.objects.order_by('id')]
205
206        class F(FilterSet):
207            author = ChoiceFilter(
208                choices=choices,
209                null_value='null',
210                null_label='NULL',
211            )
212
213            class Meta:
214                model = Article
215                fields = ['author']
216
217        # sanity check to make sure the filter is setup correctly
218        f = F({'author': '1'})
219        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: str(o.author), False)
220
221        f = F({'author': 'null'})
222        self.assertQuerysetEqual(f.qs, [None], lambda o: o.author, False)
223
224
225class MultipleChoiceFilterTests(TestCase):
226
227    def test_filtering(self):
228        User.objects.create(username='alex', status=1)
229        User.objects.create(username='jacob', status=2)
230        User.objects.create(username='aaron', status=2)
231        User.objects.create(username='carl', status=0)
232
233        class F(FilterSet):
234            status = MultipleChoiceFilter(choices=STATUS_CHOICES)
235
236            class Meta:
237                model = User
238                fields = ['status']
239
240        qs = User.objects.all().order_by('username')
241        f = F(queryset=qs)
242        self.assertQuerysetEqual(
243            f.qs, ['aaron', 'jacob', 'alex', 'carl'],
244            lambda o: o.username, False)
245
246        f = F({'status': ['0']}, queryset=qs)
247        self.assertQuerysetEqual(
248            f.qs, ['carl'], lambda o: o.username)
249
250        f = F({'status': ['0', '1']}, queryset=qs)
251        self.assertQuerysetEqual(
252            f.qs, ['alex', 'carl'], lambda o: o.username)
253
254        f = F({'status': ['0', '1', '2']}, queryset=qs)
255        self.assertQuerysetEqual(
256            f.qs, ['aaron', 'alex', 'carl', 'jacob'], lambda o: o.username)
257
258    def test_filtering_on_null_choice(self):
259        User.objects.create(username='alex', status=1)
260        User.objects.create(username='jacob', status=2)
261        User.objects.create(username='aaron', status=2)
262        User.objects.create(username='carl', status=0)
263
264        Article.objects.create(author_id=1, published=now())
265        Article.objects.create(author_id=2, published=now())
266        Article.objects.create(author_id=3, published=now())
267        Article.objects.create(author_id=4, published=now())
268        Article.objects.create(author_id=None, published=now())
269
270        choices = [(u.pk, str(u)) for u in User.objects.order_by('id')]
271
272        class F(FilterSet):
273            author = MultipleChoiceFilter(
274                choices=choices,
275                null_value='null',
276                null_label='NULL',
277            )
278
279            class Meta:
280                model = Article
281                fields = ['author']
282
283        # sanity check to make sure the filter is setup correctly
284        f = F({'author': ['1']})
285        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: str(o.author), False)
286
287        f = F({'author': ['null']})
288        self.assertQuerysetEqual(f.qs, [None], lambda o: o.author, False)
289
290        f = F({'author': ['1', 'null']})
291        self.assertQuerysetEqual(
292            f.qs, ['alex', None],
293            lambda o: o.author and str(o.author),
294            False)
295
296
297class TypedMultipleChoiceFilterTests(TestCase):
298
299    def test_filtering(self):
300        User.objects.create(username='alex', status=1)
301        User.objects.create(username='jacob', status=2)
302        User.objects.create(username='aaron', status=2)
303        User.objects.create(username='carl', status=0)
304
305        class F(FilterSet):
306            status = TypedMultipleChoiceFilter(choices=STATUS_CHOICES, coerce=lambda x: x[0:2])
307
308            class Meta:
309                model = User
310                fields = ['status']
311
312        qs = User.objects.all().order_by('username')
313        f = F(queryset=qs)
314        self.assertQuerysetEqual(
315            f.qs, ['aa', 'ja', 'al', 'ca'],
316            lambda o: o.username[0:2], False)
317
318        f = F({'status': ['0']}, queryset=qs)
319        self.assertQuerysetEqual(
320            f.qs, ['ca'], lambda o: o.username[0:2])
321
322        f = F({'status': ['0', '1']}, queryset=qs)
323        self.assertQuerysetEqual(
324            f.qs, ['al', 'ca'], lambda o: o.username[0:2])
325
326        f = F({'status': ['0', '1', '2']}, queryset=qs)
327        self.assertQuerysetEqual(
328            f.qs, ['aa', 'al', 'ca', 'ja'], lambda o: o.username[0:2])
329
330
331class DateFilterTests(TestCase):
332
333    def test_filtering(self):
334        today = now().date()
335        timestamp = now().time().replace(microsecond=0)
336        last_week = today - datetime.timedelta(days=7)
337        check_date = str(last_week)
338        u = User.objects.create(username='alex')
339        Comment.objects.create(author=u, time=timestamp, date=today)
340        Comment.objects.create(author=u, time=timestamp, date=last_week)
341        Comment.objects.create(author=u, time=timestamp, date=today)
342        Comment.objects.create(author=u, time=timestamp, date=last_week)
343
344        class F(FilterSet):
345            class Meta:
346                model = Comment
347                fields = ['date']
348
349        f = F({'date': check_date}, queryset=Comment.objects.all())
350        self.assertEqual(len(f.qs), 2)
351        self.assertQuerysetEqual(f.qs, [2, 4], lambda o: o.pk, False)
352
353
354class TimeFilterTests(TestCase):
355
356    def test_filtering(self):
357        today = now().date()
358        now_time = now().time().replace(microsecond=0)
359        ten_min_ago = (now() - datetime.timedelta(minutes=10))
360        fixed_time = ten_min_ago.time().replace(microsecond=0)
361        check_time = str(fixed_time)
362        u = User.objects.create(username='alex')
363        Comment.objects.create(author=u, time=now_time, date=today)
364        Comment.objects.create(author=u, time=fixed_time, date=today)
365        Comment.objects.create(author=u, time=now_time, date=today)
366        Comment.objects.create(author=u, time=fixed_time, date=today)
367
368        class F(FilterSet):
369            class Meta:
370                model = Comment
371                fields = ['time']
372
373        f = F({'time': check_time}, queryset=Comment.objects.all())
374        self.assertEqual(len(f.qs), 2)
375        self.assertQuerysetEqual(f.qs, [2, 4], lambda o: o.pk, False)
376
377
378class DateTimeFilterTests(TestCase):
379
380    def test_filtering(self):
381        now_dt = now()
382        ten_min_ago = now_dt - datetime.timedelta(minutes=10)
383        one_day_ago = now_dt - datetime.timedelta(days=1)
384        u = User.objects.create(username='alex')
385        Article.objects.create(author=u, published=now_dt)
386        Article.objects.create(author=u, published=ten_min_ago)
387        Article.objects.create(author=u, published=one_day_ago)
388
389        tz = timezone.get_current_timezone()
390        # make naive, like a browser would send
391        local_ten_min_ago = timezone.make_naive(ten_min_ago, tz)
392        check_dt = str(local_ten_min_ago)
393
394        class F(FilterSet):
395            class Meta:
396                model = Article
397                fields = ['published']
398
399        qs = Article.objects.all()
400        f = F({'published': ten_min_ago}, queryset=qs)
401        self.assertEqual(len(f.qs), 1)
402        self.assertQuerysetEqual(f.qs, [2], lambda o: o.pk)
403
404        # this is how it would come through a browser
405        f = F({'published': check_dt}, queryset=qs)
406        self.assertEqual(
407            len(f.qs),
408            1,
409            "%s isn't matching %s when cleaned" % (check_dt, ten_min_ago))
410        self.assertQuerysetEqual(f.qs, [2], lambda o: o.pk)
411
412
413class DurationFilterTests(TestCase):
414    """Duration filter tests.
415
416    The preferred format for durations in Django is '%d %H:%M:%S.%f'.
417    See django.utils.dateparse.parse_duration
418
419    Django is not fully ISO 8601 compliant (yet): year, month, and
420    week designators are not supported, so a duration string
421    like "P3Y6M4DT12H30M5S" cannot be used.
422    See https://en.wikipedia.org/wiki/ISO_8601#Durations
423
424    """
425    def setUp(self):
426        self.r1 = SpacewalkRecord.objects.create(
427            astronaut="Anatoly Solovyev",
428            duration=datetime.timedelta(hours=82, minutes=22))
429        self.r2 = SpacewalkRecord.objects.create(
430            astronaut="Michael Lopez-Alegria",
431            duration=datetime.timedelta(hours=67, minutes=40))
432        self.r3 = SpacewalkRecord.objects.create(
433            astronaut="Jerry L. Ross",
434            duration=datetime.timedelta(hours=58, minutes=32))
435        self.r4 = SpacewalkRecord.objects.create(
436            astronaut="John M. Grunsfeld",
437            duration=datetime.timedelta(hours=58, minutes=30))
438        self.r5 = SpacewalkRecord.objects.create(
439            astronaut="Richard Mastracchio",
440            duration=datetime.timedelta(hours=53, minutes=4))
441
442    def test_filtering(self):
443
444        class F(FilterSet):
445            class Meta:
446                model = SpacewalkRecord
447                fields = ['duration']
448
449        qs = SpacewalkRecord.objects.all()
450
451        # Django style: 3 days, 10 hours, 22 minutes.
452        f = F({'duration': '3 10:22:00'}, queryset=qs)
453        self.assertQuerysetEqual(f.qs, [self.r1], lambda x: x)
454
455        # ISO 8601: 3 days, 10 hours, 22 minutes.
456        f = F({'duration': 'P3DT10H22M'}, queryset=qs)
457        self.assertQuerysetEqual(f.qs, [self.r1], lambda x: x)
458
459        # Django style: 82 hours, 22 minutes.
460        f = F({'duration': '82:22:00'}, queryset=qs)
461        self.assertQuerysetEqual(f.qs, [self.r1], lambda x: x)
462
463        # ISO 8601: 82 hours, 22 minutes.
464        f = F({'duration': 'PT82H22M'}, queryset=qs)
465        self.assertQuerysetEqual(f.qs, [self.r1], lambda x: x)
466
467    def test_filtering_with_single_lookup_expr_dictionary(self):
468
469        class F(FilterSet):
470            class Meta:
471                model = SpacewalkRecord
472                fields = {'duration': ['gt', 'gte', 'lt', 'lte']}
473
474        qs = SpacewalkRecord.objects.order_by('-duration')
475
476        f = F({'duration__gt': 'PT58H30M'}, queryset=qs)
477        self.assertQuerysetEqual(
478            f.qs, [self.r1, self.r2, self.r3], lambda x: x)
479
480        f = F({'duration__gte': 'PT58H30M'}, queryset=qs)
481        self.assertQuerysetEqual(
482            f.qs, [self.r1, self.r2, self.r3, self.r4], lambda x: x)
483
484        f = F({'duration__lt': 'PT58H30M'}, queryset=qs)
485        self.assertQuerysetEqual(
486            f.qs, [self.r5], lambda x: x)
487
488        f = F({'duration__lte': 'PT58H30M'}, queryset=qs)
489        self.assertQuerysetEqual(
490            f.qs, [self.r4, self.r5], lambda x: x)
491
492    def test_filtering_with_multiple_lookup_exprs(self):
493
494        class F(FilterSet):
495            min_duration = DurationFilter(field_name='duration', lookup_expr='gte')
496            max_duration = DurationFilter(field_name='duration', lookup_expr='lte')
497
498            class Meta:
499                model = SpacewalkRecord
500                fields = '__all__'
501
502        qs = SpacewalkRecord.objects.order_by('duration')
503
504        f = F({'min_duration': 'PT55H', 'max_duration': 'PT60H'}, queryset=qs)
505        self.assertQuerysetEqual(f.qs, [self.r4, self.r3], lambda x: x)
506
507
508class ModelChoiceFilterTests(TestCase):
509
510    def test_filtering(self):
511        alex = User.objects.create(username='alex')
512        jacob = User.objects.create(username='jacob')
513        date = now().date()
514        time = now().time()
515        Comment.objects.create(author=jacob, time=time, date=date)
516        Comment.objects.create(author=alex, time=time, date=date)
517        Comment.objects.create(author=jacob, time=time, date=date)
518
519        class F(FilterSet):
520            class Meta:
521                model = Comment
522                fields = ['author']
523
524        qs = Comment.objects.all()
525        f = F({'author': jacob.pk}, queryset=qs)
526        self.assertQuerysetEqual(f.qs, [1, 3], lambda o: o.pk, False)
527
528    @override_settings(FILTERS_NULL_CHOICE_LABEL='No Author')
529    def test_filtering_null(self):
530        Article.objects.create(published=now())
531        alex = User.objects.create(username='alex')
532        Article.objects.create(author=alex, published=now())
533
534        class F(FilterSet):
535            class Meta:
536                model = Article
537                fields = ['author', 'name']
538
539        qs = Article.objects.all()
540        f = F({'author': 'null'}, queryset=qs)
541        self.assertQuerysetEqual(f.qs, [None], lambda o: o.author, False)
542
543    def test_callable_queryset(self):
544        # Sanity check for callable queryset arguments.
545        # Ensure that nothing is improperly cached
546        User.objects.create(username='alex')
547        jacob = User.objects.create(username='jacob')
548        aaron = User.objects.create(username='aaron')
549
550        def users(request):
551            return User.objects.filter(pk__lt=request.user.pk)
552
553        class F(FilterSet):
554            author = ModelChoiceFilter(field_name='author', queryset=users)
555
556            class Meta:
557                model = Comment
558                fields = ['author']
559
560        qs = Comment.objects.all()
561        request = mock.Mock()
562
563        request.user = jacob
564        f = F(queryset=qs, request=request).filters['author'].field
565        self.assertQuerysetEqual(f.queryset, [1], lambda o: o.pk, False)
566
567        request.user = aaron
568        f = F(queryset=qs, request=request).filters['author'].field
569        self.assertQuerysetEqual(f.queryset, [1, 2], lambda o: o.pk, False)
570
571
572class ModelMultipleChoiceFilterTests(TestCase):
573
574    def setUp(self):
575        alex = User.objects.create(username='alex')
576        User.objects.create(username='jacob')
577        aaron = User.objects.create(username='aaron')
578        b1 = Book.objects.create(title="Ender's Game", price='1.00',
579                                 average_rating=3.0)
580        b2 = Book.objects.create(title="Rainbow Six", price='1.00',
581                                 average_rating=3.0)
582        b3 = Book.objects.create(title="Snowcrash", price='1.00',
583                                 average_rating=3.0)
584        Book.objects.create(title="Stranger in a Strage Land", price='1.00',
585                            average_rating=3.0)
586        alex.favorite_books.add(b1, b2)
587        aaron.favorite_books.add(b1, b3)
588
589        self.alex = alex
590
591    def test_filtering(self):
592        class F(FilterSet):
593            class Meta:
594                model = User
595                fields = ['favorite_books']
596
597        qs = User.objects.all().order_by('username')
598        f = F({'favorite_books': ['1']}, queryset=qs)
599        self.assertQuerysetEqual(f.qs, ['aaron', 'alex'], lambda o: o.username)
600
601        f = F({'favorite_books': ['1', '3']}, queryset=qs)
602        self.assertQuerysetEqual(f.qs, ['aaron', 'alex'], lambda o: o.username)
603
604        f = F({'favorite_books': ['2']}, queryset=qs)
605        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
606
607        f = F({'favorite_books': ['4']}, queryset=qs)
608        self.assertQuerysetEqual(f.qs, [], lambda o: o.username)
609
610    @override_settings(FILTERS_NULL_CHOICE_LABEL='No Favorites')
611    def test_filtering_null(self):
612        class F(FilterSet):
613            class Meta:
614                model = User
615                fields = ['favorite_books']
616
617        qs = User.objects.all()
618        f = F({'favorite_books': ['null']}, queryset=qs)
619
620        self.assertQuerysetEqual(f.qs, ['jacob'], lambda o: o.username)
621
622    def test_filtering_dictionary(self):
623        class F(FilterSet):
624            class Meta:
625                model = User
626                fields = {'favorite_books': ['exact']}
627
628        qs = User.objects.all().order_by('username')
629        f = F({'favorite_books': ['1']}, queryset=qs)
630        self.assertQuerysetEqual(f.qs, ['aaron', 'alex'], lambda o: o.username)
631
632        f = F({'favorite_books': ['1', '3']}, queryset=qs)
633        self.assertQuerysetEqual(f.qs, ['aaron', 'alex'], lambda o: o.username)
634
635        f = F({'favorite_books': ['2']}, queryset=qs)
636        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
637
638        f = F({'favorite_books': ['4']}, queryset=qs)
639        self.assertQuerysetEqual(f.qs, [], lambda o: o.username)
640
641    def test_filtering_on_all_of_subset_of_choices(self):
642        class F(FilterSet):
643            class Meta:
644                model = User
645                fields = ['favorite_books']
646
647            def __init__(self, *args, **kwargs):
648                super().__init__(*args, **kwargs)
649                # This filter has a limited number of choices.
650                self.filters['favorite_books'].extra.update({
651                    'queryset': Book.objects.filter(id__in=[1, 2])
652                })
653
654                self.filters['favorite_books'].extra['required'] = True
655
656        qs = User.objects.all().order_by('username')
657
658        # Select all the given choices.
659        f = F({'favorite_books': ['1', '2']}, queryset=qs)
660
661        # The results should only include matching users - not Jacob.
662        self.assertQuerysetEqual(f.qs, ['aaron', 'alex'], lambda o: o.username)
663
664    def test_filtering_on_non_required_fields(self):
665        # See issue #132 - filtering with all options on a non-required
666        # field should exclude any results where the field is null.
667        class F(FilterSet):
668            author = ModelMultipleChoiceFilter(queryset=User.objects.all())
669
670            class Meta:
671                model = Article
672                fields = ['author']
673
674        published = now()
675        Article.objects.create(published=published, author=self.alex)
676        Article.objects.create(published=published, author=self.alex)
677        Article.objects.create(published=published)
678
679        qs = Article.objects.all()
680
681        # Select all authors.
682        authors = [
683            str(user.id)
684            for user in User.objects.all()
685        ]
686        f = F({'author': authors}, queryset=qs)
687
688        # The results should not include anonymous articles
689        self.assertEqual(
690            set(f.qs),
691            set(Article.objects.exclude(author__isnull=True)),
692        )
693
694
695class NumberFilterTests(TestCase):
696
697    def setUp(self):
698        Book.objects.create(title="Ender's Game", price='10.0',
699                            average_rating=4.7999999999999998)
700        Book.objects.create(title="Rainbow Six", price='15.0',
701                            average_rating=4.5999999999999996)
702        Book.objects.create(title="Snowcrash", price='20.0',
703                            average_rating=4.2999999999999998)
704
705    def test_filtering(self):
706        class F(FilterSet):
707            class Meta:
708                model = Book
709                fields = ['price']
710
711        f = F({'price': 10}, queryset=Book.objects.all())
712        self.assertQuerysetEqual(f.qs, ['Ender\'s Game'], lambda o: o.title)
713
714
715class RangeFilterTests(TestCase):
716
717    def setUp(self):
718        Book.objects.create(title="Ender's Game", price='10.0',
719                            average_rating=4.7999999999999998)
720        Book.objects.create(title="Rainbow Six", price='15.0',
721                            average_rating=4.5999999999999996)
722        Book.objects.create(title="Snowcrash", price='20.0',
723                            average_rating=4.2999999999999998)
724        Book.objects.create(title="Refund", price='-10.0',
725                            average_rating=5.0)
726        Book.objects.create(title="Free Book", price='0.0',
727                            average_rating=0.0)
728
729    def test_filtering(self):
730        class F(FilterSet):
731            price = RangeFilter()
732
733            class Meta:
734                model = Book
735                fields = ['price']
736
737        qs = Book.objects.all().order_by('title')
738        f = F(queryset=qs)
739        self.assertQuerysetEqual(f.qs,
740                                 ['Ender\'s Game', 'Free Book', 'Rainbow Six', 'Refund', 'Snowcrash'],
741                                 lambda o: o.title)
742        f = F({'price_min': '5', 'price_max': '15'}, queryset=qs)
743        self.assertQuerysetEqual(f.qs,
744                                 ['Ender\'s Game', 'Rainbow Six'],
745                                 lambda o: o.title)
746
747        f = F({'price_min': '11'}, queryset=qs)
748        self.assertQuerysetEqual(f.qs,
749                                 ['Rainbow Six', 'Snowcrash'],
750                                 lambda o: o.title)
751        f = F({'price_max': '19'}, queryset=qs)
752        self.assertQuerysetEqual(f.qs,
753                                 ['Ender\'s Game', 'Free Book', 'Rainbow Six', 'Refund'],
754                                 lambda o: o.title)
755
756        f = F({'price_min': '0', 'price_max': '12'}, queryset=qs)
757        self.assertQuerysetEqual(f.qs,
758                                 ['Ender\'s Game', 'Free Book'],
759                                 lambda o: o.title)
760        f = F({'price_min': '-11', 'price_max': '0'}, queryset=qs)
761        self.assertQuerysetEqual(f.qs,
762                                 ['Free Book', 'Refund'],
763                                 lambda o: o.title)
764        f = F({'price_min': '0', 'price_max': '0'}, queryset=qs)
765        self.assertQuerysetEqual(f.qs,
766                                 ['Free Book'],
767                                 lambda o: o.title)
768
769
770class DateRangeFilterTests(TestCase):
771
772    class CommentFilter(FilterSet):
773        date = DateRangeFilter()
774
775        class Meta:
776            model = Comment
777            fields = ['date']
778
779    @contextlib.contextmanager
780    def relative_to(self, today):
781        today = make_aware(today)
782        yesterday = today - datetime.timedelta(days=1)
783        five_days_ago = today - datetime.timedelta(days=5)
784        two_weeks_ago = today - datetime.timedelta(days=14)
785        two_months_ago = today - datetime.timedelta(days=62)
786        two_years_ago = today - datetime.timedelta(days=800)
787
788        alex = User.objects.create(username='alex')
789        time = now().time()
790        Comment.objects.create(date=two_weeks_ago, author=alex, time=time)
791        Comment.objects.create(date=two_years_ago, author=alex, time=time)
792        Comment.objects.create(date=five_days_ago, author=alex, time=time)
793        Comment.objects.create(date=today, author=alex, time=time)
794        Comment.objects.create(date=yesterday, author=alex, time=time)
795        Comment.objects.create(date=two_months_ago, author=alex, time=time)
796
797        with mock.patch('django_filters.filters.now') as mock_now:
798            mock_now.return_value = today
799            yield
800
801    def test_filtering_for_year(self):
802        f = self.CommentFilter({'date': 'year'})
803        with self.relative_to(datetime.datetime(now().year, 4, 1)):
804            self.assertQuerysetEqual(f.qs, [1, 3, 4, 5, 6], lambda o: o.pk, False)
805
806    def test_filtering_for_month(self):
807        f = self.CommentFilter({'date': 'month'})
808        with self.relative_to(datetime.datetime(now().year, 4, 21)):
809            self.assertQuerysetEqual(f.qs, [1, 3, 4, 5], lambda o: o.pk, False)
810
811    def test_filtering_for_week(self):
812        f = self.CommentFilter({'date': 'week'})
813        with self.relative_to(datetime.datetime(now().year, 1, 1)):
814            self.assertQuerysetEqual(f.qs, [3, 4, 5], lambda o: o.pk, False)
815
816    def test_filtering_for_yesterday(self):
817        f = self.CommentFilter({'date': 'yesterday'})
818        with self.relative_to(datetime.datetime(now().year, 1, 1)):
819            self.assertQuerysetEqual(f.qs, [5], lambda o: o.pk, False)
820
821    def test_filtering_for_today(self):
822        f = self.CommentFilter({'date': 'today'})
823        with self.relative_to(datetime.datetime(now().year, 1, 1)):
824            self.assertQuerysetEqual(f.qs, [4], lambda o: o.pk, False)
825
826
827class DateFromToRangeFilterTests(TestCase):
828
829    def test_filtering(self):
830        adam = User.objects.create(username='adam')
831        kwargs = {'text': 'test', 'author': adam, 'time': '10:00'}
832        Comment.objects.create(date=datetime.date(2016, 1, 1), **kwargs)
833        Comment.objects.create(date=datetime.date(2016, 1, 2), **kwargs)
834        Comment.objects.create(date=datetime.date(2016, 1, 3), **kwargs)
835        Comment.objects.create(date=datetime.date(2016, 1, 3), **kwargs)
836
837        class F(FilterSet):
838            published = DateFromToRangeFilter(field_name='date')
839
840            class Meta:
841                model = Comment
842                fields = ['date']
843
844        results = F(data={
845            'published_after': '2016-01-02',
846            'published_before': '2016-01-03'})
847        self.assertEqual(len(results.qs), 3)
848
849    def test_filtering_ignores_time(self):
850        tz = timezone.get_current_timezone()
851        Article.objects.create(
852            published=datetime.datetime(2016, 1, 1, 10, 0, tzinfo=tz))
853        Article.objects.create(
854            published=datetime.datetime(2016, 1, 2, 12, 45, tzinfo=tz))
855        Article.objects.create(
856            published=datetime.datetime(2016, 1, 3, 18, 15, tzinfo=tz))
857        Article.objects.create(
858            published=datetime.datetime(2016, 1, 3, 19, 30, tzinfo=tz))
859
860        class F(FilterSet):
861            published = DateFromToRangeFilter()
862
863            class Meta:
864                model = Article
865                fields = ['published']
866
867        results = F(data={
868            'published_after': '2016-01-02',
869            'published_before': '2016-01-03'})
870        self.assertEqual(len(results.qs), 3)
871
872    @override_settings(TIME_ZONE='America/Sao_Paulo')
873    def test_filtering_dst_start_midnight(self):
874        tz = timezone.get_default_timezone()
875        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 14, 23, 59), tz, False))
876        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 15, 0, 0), tz, False))
877        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 15, 1, 0), tz, False))
878        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 16, 0, 0), tz, False))
879
880        class F(FilterSet):
881            published = DateFromToRangeFilter()
882
883            class Meta:
884                model = Article
885                fields = ['published']
886
887        results = F(data={
888            'published_after': '2017-10-15',
889            'published_before': '2017-10-15'})
890        self.assertEqual(len(results.qs), 2)
891
892    @override_settings(TIME_ZONE='America/Sao_Paulo')
893    def test_filtering_dst_ends_midnight(self):
894        tz = timezone.get_default_timezone()
895        Article.objects.create(published=make_aware(datetime.datetime(2017, 2, 19, 0, 0), tz, False))
896        Article.objects.create(published=make_aware(datetime.datetime(2017, 2, 18, 23, 0), tz, False))
897        Article.objects.create(published=make_aware(datetime.datetime(2017, 2, 18, 0, 0), tz, False))
898        Article.objects.create(published=make_aware(datetime.datetime(2017, 2, 17, 15, 0), tz, False))
899
900        class F(FilterSet):
901            published = DateFromToRangeFilter()
902
903            class Meta:
904                model = Article
905                fields = ['published']
906
907        results = F(data={
908            'published_after': '2017-02-18',
909            'published_before': '2017-02-18'})
910        self.assertEqual(len(results.qs), 2)
911
912    @override_settings(TIME_ZONE='Europe/Paris')
913    def test_filtering_dst_start(self):
914        tz = timezone.get_default_timezone()
915        Article.objects.create(published=make_aware(datetime.datetime(2017, 3, 25, 23, 59), tz, False))
916        Article.objects.create(published=make_aware(datetime.datetime(2017, 3, 26, 0, 0), tz, False))
917        Article.objects.create(published=make_aware(datetime.datetime(2017, 3, 26, 2, 0), tz, False))
918        Article.objects.create(published=make_aware(datetime.datetime(2017, 3, 26, 3, 0), tz, False))
919        Article.objects.create(published=make_aware(datetime.datetime(2017, 3, 27, 0, 0), tz, False))
920
921        class F(FilterSet):
922            published = DateFromToRangeFilter()
923
924            class Meta:
925                model = Article
926                fields = ['published']
927
928        results = F(data={
929            'published_after': '2017-3-26',
930            'published_before': '2017-3-26'})
931        self.assertEqual(len(results.qs), 3)
932
933    @override_settings(TIME_ZONE='Europe/Paris')
934    def test_filtering_dst_end(self):
935        tz = timezone.get_default_timezone()
936        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 28, 23, 59), tz, False))
937        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 29, 0, 0), tz, False))
938        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 29, 2, 0), tz, False))
939        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 29, 3, 0), tz, False))
940        Article.objects.create(published=make_aware(datetime.datetime(2017, 10, 30, 0, 0), tz, False))
941
942        class F(FilterSet):
943            published = DateFromToRangeFilter()
944
945            class Meta:
946                model = Article
947                fields = ['published']
948
949        results = F(data={
950            'published_after': '2017-10-29',
951            'published_before': '2017-10-29'})
952        self.assertEqual(len(results.qs), 3)
953
954
955class DateTimeFromToRangeFilterTests(TestCase):
956
957    def test_filtering(self):
958        tz = timezone.get_current_timezone()
959        Article.objects.create(
960            published=datetime.datetime(2016, 1, 1, 10, 0, tzinfo=tz))
961        Article.objects.create(
962            published=datetime.datetime(2016, 1, 2, 12, 45, tzinfo=tz))
963        Article.objects.create(
964            published=datetime.datetime(2016, 1, 3, 18, 15, tzinfo=tz))
965        Article.objects.create(
966            published=datetime.datetime(2016, 1, 3, 19, 30, tzinfo=tz))
967
968        class F(FilterSet):
969            published = DateTimeFromToRangeFilter()
970
971            class Meta:
972                model = Article
973                fields = ['published']
974
975        results = F(data={
976            'published_after': '2016-01-02 10:00',
977            'published_before': '2016-01-03 19:00'})
978        self.assertEqual(len(results.qs), 2)
979
980
981@unittest.expectedFailure
982class IsoDateTimeFromToRangeFilterTests(TestCase):
983
984    def test_filtering(self):
985        tz = timezone.get_current_timezone()
986        Article.objects.create(
987            published=datetime.datetime(2016, 1, 1, 10, 0, tzinfo=tz))
988        Article.objects.create(
989            published=datetime.datetime(2016, 1, 2, 12, 45, tzinfo=tz))
990        Article.objects.create(
991            published=datetime.datetime(2016, 1, 3, 18, 15, tzinfo=tz))
992        Article.objects.create(
993            published=datetime.datetime(2016, 1, 3, 19, 30, tzinfo=tz))
994
995        class F(FilterSet):
996            published = IsoDateTimeFromToRangeFilter()
997
998            class Meta:
999                model = Article
1000                fields = ['published']
1001
1002        dt = (datetime.datetime.now(tz=tz))
1003        results = F(data={
1004            'published_after': '2016-01-02T10:00:00.000000' + dt.strftime("%z"),
1005            'published_before': '2016-01-03T19:00:00.000000' + dt.strftime("%z")})
1006        self.assertEqual(len(results.qs), 2)
1007
1008
1009class TimeRangeFilterTests(TestCase):
1010
1011    def test_filtering(self):
1012        adam = User.objects.create(username='adam')
1013        kwargs = {
1014            'text': 'test', 'author': adam, 'date': datetime.date.today()}
1015        Comment.objects.create(time='7:30', **kwargs)
1016        Comment.objects.create(time='8:00', **kwargs)
1017        Comment.objects.create(time='9:30', **kwargs)
1018        Comment.objects.create(time='11:00', **kwargs)
1019
1020        class F(FilterSet):
1021            time = TimeRangeFilter()
1022
1023            class Meta:
1024                model = Comment
1025                fields = ['time']
1026
1027        results = F(data={
1028            'time_after': '8:00',
1029            'time_before': '10:00'})
1030        self.assertEqual(len(results.qs), 2)
1031
1032
1033class AllValuesFilterTests(TestCase):
1034
1035    def test_filtering(self):
1036        User.objects.create(username='alex')
1037        User.objects.create(username='jacob')
1038        User.objects.create(username='aaron')
1039
1040        class F(FilterSet):
1041            username = AllValuesFilter()
1042
1043            class Meta:
1044                model = User
1045                fields = ['username']
1046
1047        self.assertEqual(list(F().qs), list(User.objects.all()))
1048        self.assertEqual(list(F({'username': 'alex'}).qs),
1049                         [User.objects.get(username='alex')])
1050
1051        # invalid choice
1052        self.assertFalse(F({'username': 'jose'}).is_valid())
1053        self.assertEqual(list(F({'username': 'jose'}).qs),
1054                         list(User.objects.all()))
1055
1056
1057class AllValuesMultipleFilterTests(TestCase):
1058
1059    def test_filtering(self):
1060        User.objects.create(username='alex')
1061        User.objects.create(username='jacob')
1062        User.objects.create(username='aaron')
1063
1064        class F(FilterSet):
1065            username = AllValuesMultipleFilter()
1066
1067            class Meta:
1068                model = User
1069                fields = ['username']
1070
1071        self.assertEqual(list(F().qs), list(User.objects.all()))
1072        self.assertEqual(list(F({'username': ['alex']}).qs),
1073                         [User.objects.get(username='alex')])
1074        self.assertEqual(list(F({'username': ['alex', 'jacob']}).qs),
1075                         list(User.objects.filter(username__in=['alex', 'jacob'])))
1076
1077        # invalid choice
1078        self.assertFalse(F({'username': 'jose'}).is_valid())
1079        self.assertEqual(list(F({'username': 'jose'}).qs),
1080                         list(User.objects.all()))
1081
1082
1083class FilterMethodTests(TestCase):
1084
1085    def setUp(self):
1086        User.objects.create(username='alex')
1087        User.objects.create(username='jacob')
1088        User.objects.create(username='aaron')
1089
1090    def test_filtering(self):
1091        class F(FilterSet):
1092            username = CharFilter(method='filter_username')
1093
1094            class Meta:
1095                model = User
1096                fields = ['username']
1097
1098            def filter_username(self, queryset, name, value):
1099                return queryset.filter(**{name: value})
1100
1101        self.assertEqual(list(F().qs), list(User.objects.all()))
1102        self.assertEqual(list(F({'username': 'alex'}).qs),
1103                         [User.objects.get(username='alex')])
1104        self.assertEqual(list(F({'username': 'jose'}).qs),
1105                         list())
1106
1107    def test_filtering_callable(self):
1108        def filter_username(queryset, name, value):
1109            return queryset.filter(**{name: value})
1110
1111        class F(FilterSet):
1112            username = CharFilter(method=filter_username)
1113
1114            class Meta:
1115                model = User
1116                fields = ['username']
1117
1118        self.assertEqual(list(F().qs), list(User.objects.all()))
1119        self.assertEqual(list(F({'username': 'alex'}).qs),
1120                         [User.objects.get(username='alex')])
1121        self.assertEqual(list(F({'username': 'jose'}).qs),
1122                         list())
1123
1124
1125class O2ORelationshipTests(TestCase):
1126
1127    def setUp(self):
1128        a1 = Account.objects.create(
1129            name='account1', in_good_standing=False, friendly=False)
1130        a2 = Account.objects.create(
1131            name='account2', in_good_standing=True, friendly=True)
1132        a3 = Account.objects.create(
1133            name='account3', in_good_standing=True, friendly=False)
1134        a4 = Account.objects.create(
1135            name='account4', in_good_standing=False, friendly=True)
1136        Profile.objects.create(account=a1, likes_coffee=True, likes_tea=False)
1137        Profile.objects.create(account=a2, likes_coffee=False, likes_tea=True)
1138        Profile.objects.create(account=a3, likes_coffee=True, likes_tea=True)
1139        Profile.objects.create(account=a4, likes_coffee=False, likes_tea=False)
1140
1141    def test_o2o_relation(self):
1142
1143        class F(FilterSet):
1144            class Meta:
1145                model = Profile
1146                fields = ('account',)
1147
1148        f = F()
1149        self.assertEqual(f.qs.count(), 4)
1150
1151        f = F({'account': 1})
1152        self.assertEqual(f.qs.count(), 1)
1153        self.assertQuerysetEqual(f.qs, [1], lambda o: o.pk)
1154
1155    def test_o2o_relation_dictionary(self):
1156
1157        class F(FilterSet):
1158            class Meta:
1159                model = Profile
1160                fields = {'account': ['exact'], }
1161
1162        f = F()
1163        self.assertEqual(f.qs.count(), 4)
1164
1165        f = F({'account': 1})
1166        self.assertEqual(f.qs.count(), 1)
1167        self.assertQuerysetEqual(f.qs, [1], lambda o: o.pk)
1168
1169    def test_reverse_o2o_relation(self):
1170        class F(FilterSet):
1171            class Meta:
1172                model = Account
1173                fields = ('profile',)
1174
1175        f = F()
1176        self.assertEqual(f.qs.count(), 4)
1177
1178        f = F({'profile': 1})
1179        self.assertEqual(f.qs.count(), 1)
1180        self.assertQuerysetEqual(f.qs, [1], lambda o: o.pk)
1181
1182    def test_o2o_relation_attribute(self):
1183        class F(FilterSet):
1184            class Meta:
1185                model = Profile
1186                fields = ('account__in_good_standing',)
1187
1188        f = F()
1189        self.assertEqual(f.qs.count(), 4)
1190
1191        f = F({'account__in_good_standing': '2'})
1192        self.assertEqual(f.qs.count(), 2)
1193        self.assertQuerysetEqual(f.qs, [2, 3], lambda o: o.pk, False)
1194
1195    def test_o2o_relation_attribute2(self):
1196        class F(FilterSet):
1197            class Meta:
1198                model = Profile
1199                fields = ('account__in_good_standing', 'account__friendly',)
1200
1201        f = F()
1202        self.assertEqual(f.qs.count(), 4)
1203
1204        f = F({'account__in_good_standing': '2', 'account__friendly': '2'})
1205        self.assertEqual(f.qs.count(), 1)
1206        self.assertQuerysetEqual(f.qs, [2], lambda o: o.pk)
1207
1208    def test_reverse_o2o_relation_attribute(self):
1209        class F(FilterSet):
1210            class Meta:
1211                model = Account
1212                fields = ('profile__likes_coffee',)
1213
1214        f = F()
1215        self.assertEqual(f.qs.count(), 4)
1216
1217        f = F({'profile__likes_coffee': '2'})
1218        self.assertEqual(f.qs.count(), 2)
1219        self.assertQuerysetEqual(f.qs, [1, 3], lambda o: o.pk, False)
1220
1221    def test_reverse_o2o_relation_attribute2(self):
1222        class F(FilterSet):
1223            class Meta:
1224                model = Account
1225                fields = ('profile__likes_coffee', 'profile__likes_tea')
1226
1227        f = F()
1228        self.assertEqual(f.qs.count(), 4)
1229
1230        f = F({'profile__likes_coffee': '2', 'profile__likes_tea': '2'})
1231        self.assertEqual(f.qs.count(), 1)
1232        self.assertQuerysetEqual(f.qs, [3], lambda o: o.pk)
1233
1234
1235class FKRelationshipTests(TestCase):
1236
1237    def test_fk_relation(self):
1238        company1 = Company.objects.create(name='company1')
1239        company2 = Company.objects.create(name='company2')
1240        Location.objects.create(
1241            company=company1, open_days="some", zip_code="90210")
1242        Location.objects.create(
1243            company=company2, open_days="WEEKEND", zip_code="11111")
1244        Location.objects.create(
1245            company=company1, open_days="monday", zip_code="12345")
1246
1247        class F(FilterSet):
1248            class Meta:
1249                model = Location
1250                fields = ('company',)
1251
1252        f = F()
1253        self.assertEqual(f.qs.count(), 3)
1254
1255        f = F({'company': 1})
1256        self.assertEqual(f.qs.count(), 2)
1257        self.assertQuerysetEqual(f.qs, [1, 3], lambda o: o.pk, False)
1258
1259    def test_reverse_fk_relation(self):
1260        alex = User.objects.create(username='alex')
1261        jacob = User.objects.create(username='jacob')
1262        date = now().date()
1263        time = now().time()
1264        Comment.objects.create(text='comment 1',
1265                               author=jacob, time=time, date=date)
1266        Comment.objects.create(text='comment 2',
1267                               author=alex, time=time, date=date)
1268        Comment.objects.create(text='comment 3',
1269                               author=jacob, time=time, date=date)
1270
1271        class F(FilterSet):
1272            class Meta:
1273                model = User
1274                fields = ['comments']
1275
1276        qs = User.objects.all()
1277        f = F({'comments': [2]}, queryset=qs)
1278        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
1279
1280        class F(FilterSet):
1281            comments = AllValuesFilter()
1282
1283            class Meta:
1284                model = User
1285                fields = ['comments']
1286
1287        f = F({'comments': 2}, queryset=qs)
1288        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
1289
1290    def test_fk_relation_attribute(self):
1291        now_dt = now()
1292        alex = User.objects.create(username='alex')
1293        jacob = User.objects.create(username='jacob')
1294        User.objects.create(username='aaron')
1295
1296        Article.objects.create(author=alex, published=now_dt)
1297        Article.objects.create(author=jacob, published=now_dt)
1298        Article.objects.create(author=alex, published=now_dt)
1299
1300        class F(FilterSet):
1301            class Meta:
1302                model = Article
1303                fields = ['author__username']
1304
1305        self.assertEqual(list(F.base_filters), ['author__username'])
1306        self.assertEqual(F({'author__username': 'alex'}).qs.count(), 2)
1307        self.assertEqual(F({'author__username': 'jacob'}).qs.count(), 1)
1308
1309        class F(FilterSet):
1310            author__username = AllValuesFilter()
1311
1312            class Meta:
1313                model = Article
1314                fields = ['author__username']
1315
1316        self.assertEqual(F({'author__username': 'alex'}).qs.count(), 2)
1317
1318    def test_reverse_fk_relation_attribute(self):
1319        alex = User.objects.create(username='alex')
1320        jacob = User.objects.create(username='jacob')
1321        date = now().date()
1322        time = now().time()
1323        Comment.objects.create(text='comment 1',
1324                               author=jacob, time=time, date=date)
1325        Comment.objects.create(text='comment 2',
1326                               author=alex, time=time, date=date)
1327        Comment.objects.create(text='comment 3',
1328                               author=jacob, time=time, date=date)
1329
1330        class F(FilterSet):
1331            class Meta:
1332                model = User
1333                fields = ['comments__text']
1334
1335        qs = User.objects.all()
1336        f = F({'comments__text': 'comment 2'}, queryset=qs)
1337        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
1338
1339        class F(FilterSet):
1340            comments__text = AllValuesFilter()
1341
1342            class Meta:
1343                model = User
1344                fields = ['comments__text']
1345
1346        f = F({'comments__text': 'comment 2'}, queryset=qs)
1347        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
1348
1349    @unittest.skip('todo - need correct models')
1350    def test_fk_relation_multiple_attributes(self):
1351        pass
1352
1353    @unittest.expectedFailure
1354    def test_reverse_fk_relation_multiple_attributes(self):
1355        company = Company.objects.create(name='company')
1356        Location.objects.create(
1357            company=company, open_days="some", zip_code="90210")
1358        Location.objects.create(
1359            company=company, open_days="WEEKEND", zip_code="11111")
1360
1361        class F(FilterSet):
1362            class Meta:
1363                model = Company
1364                fields = ('locations__zip_code', 'locations__open_days')
1365
1366        f = F({'locations__zip_code': '90210',
1367               'locations__open_days': 'WEEKEND'})
1368        self.assertEqual(f.qs.count(), 0)
1369
1370
1371class M2MRelationshipTests(TestCase):
1372
1373    def setUp(self):
1374        alex = User.objects.create(username='alex', status=1)
1375        User.objects.create(username='jacob', status=1)
1376        aaron = User.objects.create(username='aaron', status=1)
1377        b1 = Book.objects.create(title="Ender's Game", price='1.00',
1378                                 average_rating=3.0)
1379        b2 = Book.objects.create(title="Rainbow Six", price='2.00',
1380                                 average_rating=4.0)
1381        b3 = Book.objects.create(title="Snowcrash", price='1.00',
1382                                 average_rating=4.0)
1383        Book.objects.create(title="Stranger in a Strage Land", price='2.00',
1384                            average_rating=3.0)
1385        alex.favorite_books.add(b1, b2)
1386        aaron.favorite_books.add(b1, b3)
1387
1388    def test_m2m_relation(self):
1389        class F(FilterSet):
1390            class Meta:
1391                model = User
1392                fields = ['favorite_books']
1393
1394        qs = User.objects.all().order_by('username')
1395        f = F({'favorite_books': ['1']}, queryset=qs)
1396        self.assertQuerysetEqual(f.qs, ['aaron', 'alex'], lambda o: o.username)
1397
1398        f = F({'favorite_books': ['1', '3']}, queryset=qs)
1399        self.assertQuerysetEqual(f.qs, ['aaron', 'alex'], lambda o: o.username)
1400
1401        f = F({'favorite_books': ['2']}, queryset=qs)
1402        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
1403
1404        f = F({'favorite_books': ['4']}, queryset=qs)
1405        self.assertQuerysetEqual(f.qs, [], lambda o: o.username)
1406
1407    def test_reverse_m2m_relation(self):
1408        class F(FilterSet):
1409            class Meta:
1410                model = Book
1411                fields = ['lovers']
1412
1413        qs = Book.objects.all().order_by('title')
1414        f = F({'lovers': [1]}, queryset=qs)
1415        self.assertQuerysetEqual(
1416            f.qs, ["Ender's Game", "Rainbow Six"], lambda o: o.title)
1417
1418        class F(FilterSet):
1419            lovers = AllValuesFilter()
1420
1421            class Meta:
1422                model = Book
1423                fields = ['lovers']
1424
1425        f = F({'lovers': 1}, queryset=qs)
1426        self.assertQuerysetEqual(
1427            f.qs, ["Ender's Game", "Rainbow Six"], lambda o: o.title)
1428
1429    def test_m2m_relation_attribute(self):
1430        class F(FilterSet):
1431            class Meta:
1432                model = User
1433                fields = ['favorite_books__title']
1434
1435        qs = User.objects.all().order_by('username')
1436        f = F({'favorite_books__title': "Ender's Game"}, queryset=qs)
1437        self.assertQuerysetEqual(f.qs, ['aaron', 'alex'], lambda o: o.username)
1438
1439        f = F({'favorite_books__title': 'Rainbow Six'}, queryset=qs)
1440        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
1441
1442        class F(FilterSet):
1443            favorite_books__title = MultipleChoiceFilter()
1444
1445            class Meta:
1446                model = User
1447                fields = ['favorite_books__title']
1448
1449        f = F()
1450        self.assertEqual(
1451            len(f.filters['favorite_books__title'].field.choices), 0)
1452        # f = F({'favorite_books__title': ['1', '3']},
1453        #     queryset=qs)
1454        # self.assertQuerysetEqual(
1455        #     f.qs, ['aaron', 'alex'], lambda o: o.username)
1456
1457        class F(FilterSet):
1458            favorite_books__title = AllValuesFilter()
1459
1460            class Meta:
1461                model = User
1462                fields = ['favorite_books__title']
1463
1464        f = F({'favorite_books__title': "Snowcrash"}, queryset=qs)
1465        self.assertQuerysetEqual(f.qs, ['aaron'], lambda o: o.username)
1466
1467    def test_reverse_m2m_relation_attribute(self):
1468        class F(FilterSet):
1469            class Meta:
1470                model = Book
1471                fields = ['lovers__username']
1472
1473        qs = Book.objects.all().order_by('title')
1474        f = F({'lovers__username': "alex"}, queryset=qs)
1475        self.assertQuerysetEqual(
1476            f.qs, ["Ender's Game", "Rainbow Six"], lambda o: o.title)
1477
1478        f = F({'lovers__username': 'jacob'}, queryset=qs)
1479        self.assertQuerysetEqual(f.qs, [], lambda o: o.title)
1480
1481        class F(FilterSet):
1482            lovers__username = MultipleChoiceFilter()
1483
1484            class Meta:
1485                model = Book
1486                fields = ['lovers__username']
1487
1488        f = F()
1489        self.assertEqual(
1490            len(f.filters['lovers__username'].field.choices), 0)
1491        # f = F({'lovers__username': ['1', '3']},
1492        #     queryset=qs)
1493        # self.assertQuerysetEqual(
1494        #     f.qs, ["Ender's Game", "Rainbow Six"], lambda o: o.title)
1495
1496        class F(FilterSet):
1497            lovers__username = AllValuesFilter()
1498
1499            class Meta:
1500                model = Book
1501                fields = ['lovers__username']
1502
1503        f = F({'lovers__username': "alex"}, queryset=qs)
1504        self.assertQuerysetEqual(
1505            f.qs, ["Ender's Game", "Rainbow Six"], lambda o: o.title)
1506
1507    @unittest.expectedFailure
1508    def test_m2m_relation_multiple_attributes(self):
1509        class F(FilterSet):
1510            class Meta:
1511                model = User
1512                fields = ['favorite_books__price',
1513                          'favorite_books__average_rating']
1514
1515        qs = User.objects.all().order_by('username')
1516        f = F({'favorite_books__price': "1.00",
1517               'favorite_books__average_rating': 4.0},
1518              queryset=qs)
1519        self.assertQuerysetEqual(f.qs, ['aaron'], lambda o: o.username)
1520
1521        f = F({'favorite_books__price': "3.00",
1522               'favorite_books__average_rating': 4.0},
1523              queryset=qs)
1524        self.assertQuerysetEqual(f.qs, [], lambda o: o.username)
1525
1526    @unittest.expectedFailure
1527    def test_reverse_m2m_relation_multiple_attributes(self):
1528        class F(FilterSet):
1529            class Meta:
1530                model = Book
1531                fields = ['lovers__status', 'lovers__username']
1532
1533        qs = Book.objects.all().order_by('title')
1534        f = F({'lovers__status': 1, 'lovers__username': "alex"}, queryset=qs)
1535        self.assertQuerysetEqual(
1536            f.qs, ["Ender's Game", "Rainbow Six"], lambda o: o.title)
1537
1538        f = F({'lovers__status': 1, 'lovers__username': 'jacob'}, queryset=qs)
1539        self.assertQuerysetEqual(f.qs, [], lambda o: o.title)
1540
1541    @unittest.skip('todo')
1542    def test_fk_relation_on_m2m_relation(self):
1543        pass
1544
1545    @unittest.skip('todo')
1546    def test_fk_relation_attribute_on_m2m_relation(self):
1547        pass
1548
1549
1550class SymmetricalSelfReferentialRelationshipTests(TestCase):
1551
1552    def setUp(self):
1553        n1 = Node.objects.create(name='one')
1554        n2 = Node.objects.create(name='two')
1555        n3 = Node.objects.create(name='three')
1556        n4 = Node.objects.create(name='four')
1557        n1.adjacents.add(n2)
1558        n2.adjacents.add(n3)
1559        n2.adjacents.add(n4)
1560        n4.adjacents.add(n1)
1561
1562    def test_relation(self):
1563        class F(FilterSet):
1564            class Meta:
1565                model = Node
1566                fields = ['adjacents']
1567
1568        qs = Node.objects.all().order_by('pk')
1569        f = F({'adjacents': ['1']}, queryset=qs)
1570        self.assertQuerysetEqual(f.qs, [2, 4], lambda o: o.pk)
1571
1572
1573class NonSymmetricalSelfReferentialRelationshipTests(TestCase):
1574
1575    def setUp(self):
1576        n1 = DirectedNode.objects.create(name='one')
1577        n2 = DirectedNode.objects.create(name='two')
1578        n3 = DirectedNode.objects.create(name='three')
1579        n4 = DirectedNode.objects.create(name='four')
1580        n1.outbound_nodes.add(n2)
1581        n2.outbound_nodes.add(n3)
1582        n2.outbound_nodes.add(n4)
1583        n4.outbound_nodes.add(n1)
1584
1585    def test_forward_relation(self):
1586        class F(FilterSet):
1587            class Meta:
1588                model = DirectedNode
1589                fields = ['outbound_nodes']
1590
1591        qs = DirectedNode.objects.all().order_by('pk')
1592        f = F({'outbound_nodes': ['1']}, queryset=qs)
1593        self.assertQuerysetEqual(f.qs, [4], lambda o: o.pk)
1594
1595    def test_reverse_relation(self):
1596        class F(FilterSet):
1597            class Meta:
1598                model = DirectedNode
1599                fields = ['inbound_nodes']
1600
1601        qs = DirectedNode.objects.all().order_by('pk')
1602        f = F({'inbound_nodes': ['1']}, queryset=qs)
1603        self.assertQuerysetEqual(f.qs, [2], lambda o: o.pk)
1604
1605
1606@override_settings(TIME_ZONE='UTC')
1607class TransformedQueryExpressionFilterTests(TestCase):
1608
1609    def test_filtering(self):
1610        now_dt = now()
1611        after_5pm = now_dt.replace(hour=18)
1612        before_5pm = now_dt.replace(hour=16)
1613
1614        u = User.objects.create(username='alex')
1615        a = Article.objects.create(author=u, published=after_5pm)
1616        Article.objects.create(author=u, published=before_5pm)
1617
1618        class F(FilterSet):
1619            class Meta:
1620                model = Article
1621                fields = {'published': ['hour__gte']}
1622
1623        qs = Article.objects.all()
1624        f = F({'published__hour__gte': 17}, queryset=qs)
1625        self.assertEqual(len(f.qs), 1)
1626        self.assertQuerysetEqual(f.qs, [a.pk], lambda o: o.pk)
1627
1628
1629class LookupChoiceFilterTests(TestCase):
1630
1631    class BookFilter(FilterSet):
1632        price = LookupChoiceFilter(lookup_choices=['lt', 'gt'], field_class=forms.DecimalField)
1633
1634        class Meta:
1635            model = Book
1636            fields = ['price']
1637
1638    @classmethod
1639    def setUpTestData(cls):
1640        Book.objects.create(title="Ender's Game", price='10.0',
1641                            average_rating=4.7999999999999998)
1642        Book.objects.create(title="Rainbow Six", price='15.0',
1643                            average_rating=4.5999999999999996)
1644        Book.objects.create(title="Snowcrash", price='20.0',
1645                            average_rating=4.2999999999999998)
1646
1647    def test_filtering(self):
1648        F = self.BookFilter
1649
1650        f = F({'price': '15', 'price_lookup': 'lt'})
1651        self.assertQuerysetEqual(f.qs, ['Ender\'s Game'], lambda o: o.title)
1652        f = F({'price': '15', 'price_lookup': 'lt'})
1653        self.assertQuerysetEqual(f.qs, ['Ender\'s Game'], lambda o: o.title)
1654        f = F({'price': '', 'price_lookup': 'lt'})
1655        self.assertTrue(f.is_valid())
1656        self.assertQuerysetEqual(f.qs,
1657                                 ['Ender\'s Game', 'Rainbow Six', 'Snowcrash'],
1658                                 lambda o: o.title, ordered=False)
1659        f = F({'price': '15'})
1660        self.assertFalse(f.is_valid())
1661        self.assertQuerysetEqual(f.qs,
1662                                 ['Ender\'s Game', 'Rainbow Six', 'Snowcrash'],
1663                                 lambda o: o.title, ordered=False)
1664
1665    def test_inner_field_class_validation(self):
1666        f = self.BookFilter({'price': 'asdf', 'price_lookup': 'lt'})
1667        self.assertFalse(f.is_valid())
1668        self.assertEqual(f.errors, {
1669            'price': ['Enter a number.'],
1670        })
1671
1672    def test_lookup_choices_validation(self):
1673        f = self.BookFilter({'price': '1', 'price_lookup': 'asdf'})
1674        self.assertFalse(f.is_valid())
1675        self.assertEqual(f.errors, {
1676            'price': ['Select a valid choice. asdf is not one of the available choices.'],
1677        })
1678
1679    def test_lookup_omitted(self):
1680        f = self.BookFilter({'price': '1'})
1681        self.assertFalse(f.is_valid())
1682        self.assertEqual(f.errors, {
1683            'price': ['Select a lookup.'],
1684        })
1685
1686
1687@override_settings(TIME_ZONE='UTC')
1688class CSVFilterTests(TestCase):
1689
1690    def setUp(self):
1691        u1 = User.objects.create(username='alex', status=1)
1692        u2 = User.objects.create(username='jacob', status=2)
1693        User.objects.create(username='aaron', status=2)
1694        User.objects.create(username='carl', status=0)
1695
1696        now_dt = now()
1697        after_5pm = now_dt.replace(hour=18)
1698        before_5pm = now_dt.replace(hour=16)
1699
1700        Article.objects.create(author=u1, published=after_5pm)
1701        Article.objects.create(author=u2, published=after_5pm)
1702        Article.objects.create(author=u1, published=before_5pm)
1703        Article.objects.create(author=u2, published=before_5pm)
1704
1705        class UserFilter(FilterSet):
1706            class Meta:
1707                model = User
1708                fields = {
1709                    'username': ['in'],
1710                    'status': ['in'],
1711                }
1712
1713        class ArticleFilter(FilterSet):
1714            class Meta:
1715                model = Article
1716                fields = {
1717                    'author': ['in'],
1718                    'published': ['in'],
1719                }
1720
1721        self.user_filter = UserFilter
1722        self.article_filter = ArticleFilter
1723
1724        self.after_5pm = after_5pm.strftime('%Y-%m-%d %H:%M:%S.%f')
1725        self.before_5pm = before_5pm.strftime('%Y-%m-%d %H:%M:%S.%f')
1726
1727    def test_numeric_filtering(self):
1728        F = self.user_filter
1729        qs = User.objects.order_by('pk')
1730
1731        cases = [
1732            (None, [1, 2, 3, 4]),
1733            (QueryDict('status__in=1&status__in=2'), [2, 3]),
1734            ({'status__in': ''}, [1, 2, 3, 4]),
1735            ({'status__in': ','}, []),
1736            ({'status__in': '0'}, [4]),
1737            ({'status__in': '0,2'}, [2, 3, 4]),
1738            ({'status__in': '0,,1'}, [1, 4]),
1739            ({'status__in': '2'}, [2, 3]),
1740        ]
1741
1742        for params, expected in cases:
1743            with self.subTest(params=params, expected=expected):
1744                self.assertQuerysetEqual(F(params, queryset=qs).qs,
1745                                         expected, attrgetter('pk'))
1746
1747    def test_string_filtering(self):
1748        F = self.user_filter
1749        qs = User.objects.order_by('pk')
1750
1751        cases = [
1752            (None, [1, 2, 3, 4]),
1753            (QueryDict('username__in=alex&username__in=aaron'), [3]),
1754            ({'username__in': ''}, [1, 2, 3, 4]),
1755            ({'username__in': ','}, []),
1756            ({'username__in': 'alex'}, [1]),
1757            ({'username__in': 'alex,aaron'}, [1, 3]),
1758            ({'username__in': 'alex,,aaron'}, [1, 3]),
1759            ({'username__in': 'alex,'}, [1]),
1760        ]
1761
1762        for params, expected in cases:
1763            with self.subTest(params=params, expected=expected):
1764                self.assertQuerysetEqual(F(params, queryset=qs).qs,
1765                                         expected, attrgetter('pk'))
1766
1767    def test_datetime_filtering(self):
1768        F = self.article_filter
1769        qs = Article.objects.order_by('pk')
1770
1771        after = self.after_5pm
1772        before = self.before_5pm
1773
1774        cases = [
1775            (None, [1, 2, 3, 4]),
1776            (QueryDict('published__in=%s&published__in=%s' % (after, before)), [3, 4]),
1777            ({'published__in': ''}, [1, 2, 3, 4]),
1778            ({'published__in': ','}, []),
1779            ({'published__in': '%s' % (after, )}, [1, 2]),
1780            ({'published__in': '%s,%s' % (after, before, )}, [1, 2, 3, 4]),
1781            ({'published__in': '%s,,%s' % (after, before, )}, [1, 2, 3, 4]),
1782            ({'published__in': '%s,' % (after, )}, [1, 2]),
1783        ]
1784
1785        for params, expected in cases:
1786            with self.subTest(params=params, expected=expected):
1787                self.assertQuerysetEqual(F(params, queryset=qs).qs,
1788                                         expected, attrgetter('pk'))
1789
1790    def test_related_filtering(self):
1791        F = self.article_filter
1792        qs = Article.objects.order_by('pk')
1793
1794        cases = [
1795            (None, [1, 2, 3, 4]),
1796            (QueryDict('author__in=1&author__in=2'), [2, 4]),
1797            ({'author__in': ''}, [1, 2, 3, 4]),
1798            ({'author__in': ','}, []),
1799            ({'author__in': '1'}, [1, 3]),
1800            ({'author__in': '1,2'}, [1, 2, 3, 4]),
1801            ({'author__in': '1,,2'}, [1, 2, 3, 4]),
1802            ({'author__in': '1,'}, [1, 3]),
1803        ]
1804
1805        for params, expected in cases:
1806            with self.subTest(params=params, expected=expected):
1807                self.assertQuerysetEqual(F(params, queryset=qs).qs,
1808                                         expected, attrgetter('pk'))
1809
1810
1811@override_settings(TIME_ZONE='UTC')
1812class CSVRangeFilterTests(TestCase):
1813
1814    class ArticleFilter(FilterSet):
1815        class Meta:
1816            model = Article
1817            fields = {
1818                'published': ['range'],
1819            }
1820
1821    @classmethod
1822    def setUpTestData(cls):
1823        u1 = User.objects.create(username='alex', status=1)
1824        u2 = User.objects.create(username='jacob', status=2)
1825        User.objects.create(username='aaron', status=2)
1826        User.objects.create(username='carl', status=0)
1827
1828        now_dt = now()
1829        after_5pm = now_dt.replace(hour=18)
1830        around_5pm = now_dt.replace(hour=17)
1831        before_5pm = now_dt.replace(hour=16)
1832
1833        Article.objects.create(author=u1, published=after_5pm)
1834        Article.objects.create(author=u2, published=around_5pm)
1835        Article.objects.create(author=u1, published=around_5pm)
1836        Article.objects.create(author=u2, published=before_5pm)
1837
1838        cls.after_5pm = after_5pm.strftime('%Y-%m-%d %H:%M:%S.%f')
1839        cls.around_5pm = around_5pm.strftime('%Y-%m-%d %H:%M:%S.%f')
1840        cls.before_5pm = before_5pm.strftime('%Y-%m-%d %H:%M:%S.%f')
1841
1842    def test_filtering(self):
1843        F = self.ArticleFilter
1844
1845        f = F()
1846        self.assertEqual(f.qs.count(), 4)
1847
1848        # empty value is a noop
1849        f = F({'published__range': ''})
1850        self.assertTrue(f.is_valid())
1851        self.assertEqual(f.qs.count(), 4)
1852
1853        # empty values are interpreted as None types
1854        f = F({'published__range': ','})
1855        self.assertEqual(f.qs.count(), 0)
1856
1857        f = F({'published__range': '%s' % (self.before_5pm, )})
1858        self.assertFalse(f.is_valid())
1859
1860        f = F({'published__range': '%s,%s' % (self.before_5pm, self.around_5pm, )})
1861        self.assertEqual(f.qs.count(), 3)
1862
1863        f = F({'published__range': '%s,,%s' % (self.before_5pm, self.after_5pm, )})
1864        self.assertFalse(f.is_valid())
1865
1866        # empty value is interpreted as None type
1867        f = F({'published__range': '%s,' % (self.before_5pm, )})
1868        self.assertEqual(f.qs.count(), 0)
1869
1870
1871class OrderingFilterTests(TestCase):
1872
1873    def setUp(self):
1874        User.objects.create(username='alex', status=1)
1875        User.objects.create(username='jacob', status=2)
1876        User.objects.create(username='aaron', status=2)
1877        User.objects.create(username='carl', status=0)
1878
1879    def test_ordering(self):
1880        class F(FilterSet):
1881            o = OrderingFilter(
1882                fields=('username', )
1883            )
1884
1885            class Meta:
1886                model = User
1887                fields = ['username']
1888
1889        qs = User.objects.all()
1890        f = F({'o': 'username'}, queryset=qs)
1891        names = f.qs.values_list('username', flat=True)
1892        self.assertEqual(list(names), ['aaron', 'alex', 'carl', 'jacob'])
1893
1894    def test_ordering_with_select_widget(self):
1895        class F(FilterSet):
1896            o = OrderingFilter(
1897                widget=forms.Select,
1898                fields=('username', )
1899            )
1900
1901            class Meta:
1902                model = User
1903                fields = ['username']
1904
1905        qs = User.objects.all()
1906        f = F({'o': 'username'}, queryset=qs)
1907        names = f.qs.values_list('username', flat=True)
1908        self.assertEqual(list(names), ['aaron', 'alex', 'carl', 'jacob'])
1909
1910
1911class MiscFilterSetTests(TestCase):
1912
1913    def setUp(self):
1914        User.objects.create(username='alex', status=1)
1915        User.objects.create(username='jacob', status=2)
1916        User.objects.create(username='aaron', status=2)
1917        User.objects.create(username='carl', status=0)
1918
1919    def test_filtering_with_declared_filters(self):
1920        class F(FilterSet):
1921            account = CharFilter(field_name='username')
1922
1923            class Meta:
1924                model = User
1925                fields = ['account']
1926
1927        qs = MockQuerySet()
1928        F({'account': 'jdoe'}, queryset=qs).qs
1929        qs.all.return_value.filter.assert_called_with(username__exact='jdoe')
1930
1931    def test_filtering_without_meta(self):
1932        class F(FilterSet):
1933            username = CharFilter()
1934
1935        f = F({'username': 'alex'}, queryset=User.objects.all())
1936        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
1937
1938    def test_filtering_with_multiple_filters(self):
1939        class F(FilterSet):
1940            class Meta:
1941                model = User
1942                fields = ['status', 'username']
1943
1944        qs = User.objects.all()
1945
1946        f = F({'username': 'alex', 'status': '1'}, queryset=qs)
1947        self.assertQuerysetEqual(f.qs, ['alex'], lambda o: o.username)
1948
1949        f = F({'username': 'alex', 'status': '2'}, queryset=qs)
1950        self.assertQuerysetEqual(f.qs, [], lambda o: o.pk)
1951
1952    def test_filter_with_initial(self):
1953        # Initial values are a form presentation option - the FilterSet should
1954        # not use an initial value as a default value to filter by.
1955        class F(FilterSet):
1956            status = ChoiceFilter(choices=STATUS_CHOICES, initial=1)
1957
1958            class Meta:
1959                model = User
1960                fields = ['status']
1961
1962        qs = User.objects.all()
1963        users = ['alex', 'jacob', 'aaron', 'carl']
1964
1965        f = F(queryset=qs)
1966        self.assertQuerysetEqual(f.qs.order_by('pk'), users, lambda o: o.username)
1967
1968        f = F({'status': 0}, queryset=qs)
1969        self.assertQuerysetEqual(f.qs, ['carl'], lambda o: o.username)
1970
1971    def test_qs_count(self):
1972        class F(FilterSet):
1973            class Meta:
1974                model = User
1975                fields = ['status']
1976
1977        qs = User.objects.all()
1978        f = F(queryset=qs)
1979        self.assertEqual(len(f.qs), 4)
1980        self.assertEqual(f.qs.count(), 4)
1981
1982        f = F({'status': '0'}, queryset=qs)
1983        self.assertEqual(len(f.qs), 1)
1984        self.assertEqual(f.qs.count(), 1)
1985
1986        f = F({'status': '1'}, queryset=qs)
1987        self.assertEqual(len(f.qs), 1)
1988        self.assertEqual(f.qs.count(), 1)
1989
1990        f = F({'status': '2'}, queryset=qs)
1991        self.assertEqual(len(f.qs), 2)
1992        self.assertEqual(f.qs.count(), 2)
1993