@@ -519,6 +519,168 @@ class Meta:
519519 self .assertTableNotExists (Author )
520520
521521
522+ class EmbeddedModelsTopLevelIndexTest (TestMixin , TransactionTestCase ):
523+ @isolate_apps ("schema_" )
524+ def test_unique_together (self ):
525+ """Meta.unique_together defined at the top-level for embedded fields."""
526+
527+ class Address (EmbeddedModel ):
528+ unique_together_one = models .CharField (max_length = 10 )
529+ unique_together_two = models .CharField (max_length = 10 )
530+
531+ class Meta :
532+ app_label = "schema_"
533+
534+ class Author (EmbeddedModel ):
535+ address = EmbeddedModelField (Address )
536+ unique_together_three = models .CharField (max_length = 10 )
537+ unique_together_four = models .CharField (max_length = 10 )
538+
539+ class Meta :
540+ app_label = "schema_"
541+
542+ class Book (models .Model ):
543+ author = EmbeddedModelField (Author )
544+
545+ class Meta :
546+ app_label = "schema_"
547+ unique_together = [
548+ ("author__unique_together_three" , "author__unique_together_four" ),
549+ (
550+ "author__address__unique_together_one" ,
551+ "author__address__unique_together_two" ,
552+ ),
553+ ]
554+
555+ with connection .schema_editor () as editor :
556+ editor .create_model (Book )
557+ self .assertTableExists (Book )
558+ # Embedded uniques are created from top-level definition.
559+ self .assertEqual (
560+ self .get_constraints_for_columns (
561+ Book , ["author.unique_together_three" , "author.unique_together_four" ]
562+ ),
563+ [
564+ "schema__book_author.unique_together_three_author.unique_together_four_09a570b8_uniq"
565+ ],
566+ )
567+ self .assertEqual (
568+ self .get_constraints_for_columns (
569+ Book ,
570+ ["author.address.unique_together_one" , "author.address.unique_together_two" ],
571+ ),
572+ [
573+ "schema__book_author.address.unique_together_one_author.address.unique_together_two_2c2d1477_uniq"
574+ ],
575+ )
576+ editor .delete_model (Book )
577+ self .assertTableNotExists (Book )
578+
579+ @isolate_apps ("schema_" )
580+ def test_add_remove_field_indexes (self ):
581+ """AddField/RemoveField + EmbeddedModelField + Meta.indexes at top-level."""
582+
583+ class Address (EmbeddedModel ):
584+ indexed_one = models .CharField (max_length = 10 )
585+
586+ class Meta :
587+ app_label = "schema_"
588+
589+ class Author (EmbeddedModel ):
590+ address = EmbeddedModelField (Address )
591+ indexed_two = models .CharField (max_length = 10 )
592+
593+ class Meta :
594+ app_label = "schema_"
595+
596+ class Book (models .Model ):
597+ author = EmbeddedModelField (Author )
598+
599+ class Meta :
600+ app_label = "schema_"
601+ indexes = [
602+ models .Index (fields = ["author__indexed_two" ]),
603+ models .Index (fields = ["author__address__indexed_one" ]),
604+ ]
605+
606+ new_field = EmbeddedModelField (Author )
607+ new_field .set_attributes_from_name ("author" )
608+
609+ with connection .schema_editor () as editor :
610+ # Create the table and add the field.
611+ editor .create_model (Book )
612+ editor .add_field (Book , new_field )
613+ # Embedded indexes are created.
614+ self .assertEqual (
615+ self .get_constraints_for_columns (Book , ["author.indexed_two" ]),
616+ ["schema__boo_author._333c90_idx" ],
617+ )
618+ self .assertEqual (
619+ self .get_constraints_for_columns (
620+ Book ,
621+ ["author.address.indexed_one" ],
622+ ),
623+ ["schema__boo_author._f54386_idx" ],
624+ )
625+ editor .delete_model (Book )
626+ self .assertTableNotExists (Book )
627+
628+ @isolate_apps ("schema_" )
629+ def test_add_remove_field_constraints (self ):
630+ """AddField/RemoveField + EmbeddedModelField + Meta.constraints at top-level."""
631+
632+ class Address (EmbeddedModel ):
633+ unique_constraint_one = models .CharField (max_length = 10 )
634+
635+ class Meta :
636+ app_label = "schema_"
637+
638+ class Author (EmbeddedModel ):
639+ address = EmbeddedModelField (Address )
640+ unique_constraint_two = models .CharField (max_length = 10 )
641+
642+ class Meta :
643+ app_label = "schema_"
644+
645+ class Book (models .Model ):
646+ author = EmbeddedModelField (Author )
647+
648+ class Meta :
649+ app_label = "schema_"
650+ constraints = [
651+ models .UniqueConstraint (
652+ fields = ["author__unique_constraint_two" ],
653+ name = "unique_two" ,
654+ ),
655+ models .UniqueConstraint (
656+ fields = ["author__address__unique_constraint_one" ],
657+ name = "unique_one" ,
658+ ),
659+ ]
660+
661+ new_field = EmbeddedModelField (Author )
662+ new_field .set_attributes_from_name ("author" )
663+
664+ with connection .schema_editor () as editor :
665+ # Create the table and add the field.
666+ editor .create_model (Book )
667+ editor .add_field (Book , new_field )
668+ # Embedded constraints are created.
669+ self .assertEqual (
670+ self .get_constraints_for_columns (Book , ["author.unique_constraint_two" ]),
671+ ["unique_two" ],
672+ )
673+ self .assertEqual (
674+ self .get_constraints_for_columns (
675+ Book ,
676+ ["author.address.unique_constraint_one" ],
677+ ),
678+ ["unique_one" ],
679+ )
680+ editor .delete_model (Book )
681+ self .assertTableNotExists (Book )
682+
683+
522684class EmbeddedModelsIgnoredTests (TestMixin , TransactionTestCase ):
523685 def test_embedded_not_created (self ):
524686 """create_model() and delete_model() ignore EmbeddedModel."""
0 commit comments