|
1 | 1 | import itertools
|
2 | 2 |
|
3 | 3 | from django.db import connection, models
|
| 4 | +from django.db.models import Index |
4 | 5 | from django.test import TransactionTestCase, skipUnlessDBFeature
|
5 | 6 | from django.test.utils import isolate_apps
|
6 | 7 |
|
@@ -519,6 +520,217 @@ class Meta:
|
519 | 520 | self.assertTableNotExists(Author)
|
520 | 521 |
|
521 | 522 |
|
| 523 | +class EmbeddedModelsTopLevelIndexTest(TestMixin, TransactionTestCase): |
| 524 | + @isolate_apps("schema_") |
| 525 | + def test_example(self): |
| 526 | + class Author(EmbeddedModel): |
| 527 | + name = models.CharField(max_length=10) |
| 528 | + |
| 529 | + class Meta: |
| 530 | + app_label = "schema_" |
| 531 | + |
| 532 | + class Book(models.Model): |
| 533 | + name = models.CharField(max_length=100) |
| 534 | + author = EmbeddedModelField(Author) |
| 535 | + |
| 536 | + class Meta: |
| 537 | + app_label = "schema_" |
| 538 | + indexes = [Index(fields=["author__name"])] |
| 539 | + |
| 540 | + with connection.schema_editor() as editor: |
| 541 | + editor.create_model(Book) |
| 542 | + constraint = self.get_constraints(Book._meta.db_table) |
| 543 | + self.assertEqual( |
| 544 | + constraint["schema__boo_author._f231db_idx"]["columns"], ["author.name"] |
| 545 | + ) |
| 546 | + |
| 547 | + @isolate_apps("schema_") |
| 548 | + def test_unique_together(self): |
| 549 | + """Meta.unique_together defined at the top-level for embedded fields.""" |
| 550 | + |
| 551 | + class Address(EmbeddedModel): |
| 552 | + unique_together_one = models.CharField(max_length=10) |
| 553 | + unique_together_two = models.CharField(max_length=10) |
| 554 | + |
| 555 | + class Meta: |
| 556 | + app_label = "schema_" |
| 557 | + |
| 558 | + class Author(EmbeddedModel): |
| 559 | + address = EmbeddedModelField(Address) |
| 560 | + unique_together_three = models.CharField(max_length=10) |
| 561 | + unique_together_four = models.CharField(max_length=10) |
| 562 | + |
| 563 | + class Meta: |
| 564 | + app_label = "schema_" |
| 565 | + |
| 566 | + class Book(models.Model): |
| 567 | + author = EmbeddedModelField(Author) |
| 568 | + |
| 569 | + class Meta: |
| 570 | + app_label = "schema_" |
| 571 | + unique_together = [ |
| 572 | + ("author__unique_together_three", "author__unique_together_four"), |
| 573 | + ( |
| 574 | + "author__address__unique_together_one", |
| 575 | + "author__address__unique_together_two", |
| 576 | + ), |
| 577 | + ] |
| 578 | + |
| 579 | + with connection.schema_editor() as editor: |
| 580 | + editor.create_model(Book) |
| 581 | + self.assertTableExists(Book) |
| 582 | + # Embedded uniques are created from top-level definition. |
| 583 | + self.assertEqual( |
| 584 | + self.get_constraints_for_columns( |
| 585 | + Book, ["author.unique_together_three", "author.unique_together_four"] |
| 586 | + ), |
| 587 | + [ |
| 588 | + "schema__book_author.unique_together_three_author.unique_together_four_09a570b8_uniq" |
| 589 | + ], |
| 590 | + ) |
| 591 | + self.assertEqual( |
| 592 | + self.get_constraints_for_columns( |
| 593 | + Book, |
| 594 | + ["author.address.unique_together_one", "author.address.unique_together_two"], |
| 595 | + ), |
| 596 | + [ |
| 597 | + "schema__book_author.address.unique_together_one_author.address.unique_together_two_2c2d1477_uniq" |
| 598 | + ], |
| 599 | + ) |
| 600 | + editor.delete_model(Book) |
| 601 | + self.assertTableNotExists(Book) |
| 602 | + |
| 603 | + @isolate_apps("schema_") |
| 604 | + def test_add_remove_field_indexes(self): |
| 605 | + """AddField/RemoveField + EmbeddedModelField + Meta.indexes at top-level.""" |
| 606 | + |
| 607 | + class Address(EmbeddedModel): |
| 608 | + indexed_one = models.CharField(max_length=10) |
| 609 | + |
| 610 | + class Meta: |
| 611 | + app_label = "schema_" |
| 612 | + |
| 613 | + class Author(EmbeddedModel): |
| 614 | + address = EmbeddedModelField(Address) |
| 615 | + indexed_two = models.CharField(max_length=10) |
| 616 | + |
| 617 | + class Meta: |
| 618 | + app_label = "schema_" |
| 619 | + |
| 620 | + class Book(models.Model): |
| 621 | + author = EmbeddedModelField(Author) |
| 622 | + |
| 623 | + class Meta: |
| 624 | + app_label = "schema_" |
| 625 | + indexes = [ |
| 626 | + models.Index(fields=["author__indexed_two"]), |
| 627 | + models.Index(fields=["author__address__indexed_one"]), |
| 628 | + ] |
| 629 | + |
| 630 | + new_field = EmbeddedModelField(Author) |
| 631 | + new_field.set_attributes_from_name("author") |
| 632 | + |
| 633 | + with connection.schema_editor() as editor: |
| 634 | + # Create the table and add the field. |
| 635 | + editor.create_model(Book) |
| 636 | + editor.add_field(Book, new_field) |
| 637 | + # Embedded indexes are created. |
| 638 | + self.assertEqual( |
| 639 | + self.get_constraints_for_columns(Book, ["author.indexed_two"]), |
| 640 | + ["schema__boo_author._333c90_idx"], |
| 641 | + ) |
| 642 | + self.assertEqual( |
| 643 | + self.get_constraints_for_columns( |
| 644 | + Book, |
| 645 | + ["author.address.indexed_one"], |
| 646 | + ), |
| 647 | + ["schema__boo_author._f54386_idx"], |
| 648 | + ) |
| 649 | + editor.remove_field(Book, new_field) |
| 650 | + # Embedded indexes are removed. |
| 651 | + self.assertEqual( |
| 652 | + self.get_constraints_for_columns(Book, ["author.indexed_two"]), |
| 653 | + [], |
| 654 | + ) |
| 655 | + self.assertEqual( |
| 656 | + self.get_constraints_for_columns( |
| 657 | + Book, |
| 658 | + ["author.address.indexed_one"], |
| 659 | + ), |
| 660 | + [], |
| 661 | + ) |
| 662 | + editor.delete_model(Book) |
| 663 | + self.assertTableNotExists(Book) |
| 664 | + |
| 665 | + @isolate_apps("schema_") |
| 666 | + def test_add_remove_field_constraints(self): |
| 667 | + """AddField/RemoveField + EmbeddedModelField + Meta.constraints at top-level.""" |
| 668 | + |
| 669 | + class Address(EmbeddedModel): |
| 670 | + unique_constraint_one = models.CharField(max_length=10) |
| 671 | + |
| 672 | + class Meta: |
| 673 | + app_label = "schema_" |
| 674 | + |
| 675 | + class Author(EmbeddedModel): |
| 676 | + address = EmbeddedModelField(Address) |
| 677 | + unique_constraint_two = models.CharField(max_length=10) |
| 678 | + |
| 679 | + class Meta: |
| 680 | + app_label = "schema_" |
| 681 | + |
| 682 | + class Book(models.Model): |
| 683 | + author = EmbeddedModelField(Author) |
| 684 | + |
| 685 | + class Meta: |
| 686 | + app_label = "schema_" |
| 687 | + constraints = [ |
| 688 | + models.UniqueConstraint( |
| 689 | + fields=["author__unique_constraint_two"], |
| 690 | + name="unique_two", |
| 691 | + ), |
| 692 | + models.UniqueConstraint( |
| 693 | + fields=["author__address__unique_constraint_one"], |
| 694 | + name="unique_one", |
| 695 | + ), |
| 696 | + ] |
| 697 | + |
| 698 | + new_field = EmbeddedModelField(Author) |
| 699 | + new_field.set_attributes_from_name("author") |
| 700 | + |
| 701 | + with connection.schema_editor() as editor: |
| 702 | + # Create the table and add the field. |
| 703 | + editor.create_model(Book) |
| 704 | + editor.add_field(Book, new_field) |
| 705 | + # Embedded constraints are created. |
| 706 | + self.assertEqual( |
| 707 | + self.get_constraints_for_columns(Book, ["author.unique_constraint_two"]), |
| 708 | + ["unique_two"], |
| 709 | + ) |
| 710 | + self.assertEqual( |
| 711 | + self.get_constraints_for_columns( |
| 712 | + Book, |
| 713 | + ["author.address.unique_constraint_one"], |
| 714 | + ), |
| 715 | + ["unique_one"], |
| 716 | + ) |
| 717 | + editor.remove_field(Book, new_field) |
| 718 | + # Embedded constraints are removed. |
| 719 | + self.assertEqual( |
| 720 | + self.get_constraints_for_columns(Book, ["author.unique_constraint_two"]), |
| 721 | + [], |
| 722 | + ) |
| 723 | + self.assertEqual( |
| 724 | + self.get_constraints_for_columns( |
| 725 | + Book, |
| 726 | + ["author.address.unique_constraint_one"], |
| 727 | + ), |
| 728 | + [], |
| 729 | + ) |
| 730 | + editor.delete_model(Book) |
| 731 | + self.assertTableNotExists(Book) |
| 732 | + |
| 733 | + |
522 | 734 | class EmbeddedModelsIgnoredTests(TestMixin, TransactionTestCase):
|
523 | 735 | def test_embedded_not_created(self):
|
524 | 736 | """create_model() and delete_model() ignore EmbeddedModel."""
|
|
0 commit comments