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