Ticket #16681: django-invalid-model-tests.diff
File django-invalid-model-tests.diff, 56.2 KB (added by , 13 years ago) |
---|
-
new file tests/modeltests/invalid_models/invalid_models/models.py
diff -r 9a1f08c480bf tests/modeltests/invalid_models/invalid_models/models.py
- + 1 """ 2 26. Invalid models 3 4 This example exists purely to point out errors in models. 5 """ 6 7 from django.db import models 8 9 class FieldErrors(models.Model): 10 charfield = models.CharField() 11 charfield2 = models.CharField(max_length=-1) 12 charfield3 = models.CharField(max_length="bad") 13 decimalfield = models.DecimalField() 14 decimalfield2 = models.DecimalField(max_digits=-1, decimal_places=-1) 15 decimalfield3 = models.DecimalField(max_digits="bad", decimal_places="bad") 16 decimalfield4 = models.DecimalField(max_digits=9, decimal_places=10) 17 decimalfield5 = models.DecimalField(max_digits=10, decimal_places=10) 18 filefield = models.FileField() 19 choices = models.CharField(max_length=10, choices='bad') 20 choices2 = models.CharField(max_length=10, choices=[(1,2,3),(1,2,3)]) 21 index = models.CharField(max_length=10, db_index='bad') 22 field_ = models.CharField(max_length=10) 23 nullbool = models.BooleanField(null=True) 24 25 class Target(models.Model): 26 tgt_safe = models.CharField(max_length=10) 27 clash1 = models.CharField(max_length=10) 28 clash2 = models.CharField(max_length=10) 29 30 clash1_set = models.CharField(max_length=10) 31 32 class Clash1(models.Model): 33 src_safe = models.CharField(max_length=10) 34 35 foreign = models.ForeignKey(Target) 36 m2m = models.ManyToManyField(Target) 37 38 class Clash2(models.Model): 39 src_safe = models.CharField(max_length=10) 40 41 foreign_1 = models.ForeignKey(Target, related_name='id') 42 foreign_2 = models.ForeignKey(Target, related_name='src_safe') 43 44 m2m_1 = models.ManyToManyField(Target, related_name='id') 45 m2m_2 = models.ManyToManyField(Target, related_name='src_safe') 46 47 class Target2(models.Model): 48 clash3 = models.CharField(max_length=10) 49 foreign_tgt = models.ForeignKey(Target) 50 clashforeign_set = models.ForeignKey(Target) 51 52 m2m_tgt = models.ManyToManyField(Target) 53 clashm2m_set = models.ManyToManyField(Target) 54 55 class Clash3(models.Model): 56 src_safe = models.CharField(max_length=10) 57 58 foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt') 59 foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt') 60 61 m2m_1 = models.ManyToManyField(Target2, related_name='foreign_tgt') 62 m2m_2 = models.ManyToManyField(Target2, related_name='m2m_tgt') 63 64 class ClashForeign(models.Model): 65 foreign = models.ForeignKey(Target2) 66 67 class ClashM2M(models.Model): 68 m2m = models.ManyToManyField(Target2) 69 70 class SelfClashForeign(models.Model): 71 src_safe = models.CharField(max_length=10) 72 selfclashforeign = models.CharField(max_length=10) 73 74 selfclashforeign_set = models.ForeignKey("SelfClashForeign") 75 foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id') 76 foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe') 77 78 class ValidM2M(models.Model): 79 src_safe = models.CharField(max_length=10) 80 validm2m = models.CharField(max_length=10) 81 82 # M2M fields are symmetrical by default. Symmetrical M2M fields 83 # on self don't require a related accessor, so many potential 84 # clashes are avoided. 85 validm2m_set = models.ManyToManyField("self") 86 87 m2m_1 = models.ManyToManyField("self", related_name='id') 88 m2m_2 = models.ManyToManyField("self", related_name='src_safe') 89 90 m2m_3 = models.ManyToManyField('self') 91 m2m_4 = models.ManyToManyField('self') 92 93 class SelfClashM2M(models.Model): 94 src_safe = models.CharField(max_length=10) 95 selfclashm2m = models.CharField(max_length=10) 96 97 # Non-symmetrical M2M fields _do_ have related accessors, so 98 # there is potential for clashes. 99 selfclashm2m_set = models.ManyToManyField("self", symmetrical=False) 100 101 m2m_1 = models.ManyToManyField("self", related_name='id', symmetrical=False) 102 m2m_2 = models.ManyToManyField("self", related_name='src_safe', symmetrical=False) 103 104 m2m_3 = models.ManyToManyField('self', symmetrical=False) 105 m2m_4 = models.ManyToManyField('self', symmetrical=False) 106 107 class Model(models.Model): 108 "But it's valid to call a model Model." 109 year = models.PositiveIntegerField() #1960 110 make = models.CharField(max_length=10) #Aston Martin 111 name = models.CharField(max_length=10) #DB 4 GT 112 113 class Car(models.Model): 114 colour = models.CharField(max_length=5) 115 model = models.ForeignKey(Model) 116 117 class MissingRelations(models.Model): 118 rel1 = models.ForeignKey("Rel1") 119 rel2 = models.ManyToManyField("Rel2") 120 121 class MissingManualM2MModel(models.Model): 122 name = models.CharField(max_length=5) 123 missing_m2m = models.ManyToManyField(Model, through="MissingM2MModel") 124 125 class Person(models.Model): 126 name = models.CharField(max_length=5) 127 128 class Group(models.Model): 129 name = models.CharField(max_length=5) 130 primary = models.ManyToManyField(Person, through="Membership", related_name="primary") 131 secondary = models.ManyToManyField(Person, through="Membership", related_name="secondary") 132 tertiary = models.ManyToManyField(Person, through="RelationshipDoubleFK", related_name="tertiary") 133 134 class GroupTwo(models.Model): 135 name = models.CharField(max_length=5) 136 primary = models.ManyToManyField(Person, through="Membership") 137 secondary = models.ManyToManyField(Group, through="MembershipMissingFK") 138 139 class Membership(models.Model): 140 person = models.ForeignKey(Person) 141 group = models.ForeignKey(Group) 142 not_default_or_null = models.CharField(max_length=5) 143 144 class MembershipMissingFK(models.Model): 145 person = models.ForeignKey(Person) 146 147 class PersonSelfRefM2M(models.Model): 148 name = models.CharField(max_length=5) 149 friends = models.ManyToManyField('self', through="Relationship") 150 too_many_friends = models.ManyToManyField('self', through="RelationshipTripleFK") 151 152 class PersonSelfRefM2MExplicit(models.Model): 153 name = models.CharField(max_length=5) 154 friends = models.ManyToManyField('self', through="ExplicitRelationship", symmetrical=True) 155 156 class Relationship(models.Model): 157 first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set") 158 second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set") 159 date_added = models.DateTimeField() 160 161 class ExplicitRelationship(models.Model): 162 first = models.ForeignKey(PersonSelfRefM2MExplicit, related_name="rel_from_set") 163 second = models.ForeignKey(PersonSelfRefM2MExplicit, related_name="rel_to_set") 164 date_added = models.DateTimeField() 165 166 class RelationshipTripleFK(models.Model): 167 first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set_2") 168 second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set_2") 169 third = models.ForeignKey(PersonSelfRefM2M, related_name="too_many_by_far") 170 date_added = models.DateTimeField() 171 172 class RelationshipDoubleFK(models.Model): 173 first = models.ForeignKey(Person, related_name="first_related_name") 174 second = models.ForeignKey(Person, related_name="second_related_name") 175 third = models.ForeignKey(Group, related_name="rel_to_set") 176 date_added = models.DateTimeField() 177 178 class AbstractModel(models.Model): 179 name = models.CharField(max_length=10) 180 class Meta: 181 abstract = True 182 183 class AbstractRelationModel(models.Model): 184 fk1 = models.ForeignKey('AbstractModel') 185 fk2 = models.ManyToManyField('AbstractModel') 186 187 class UniqueM2M(models.Model): 188 """ Model to test for unique ManyToManyFields, which are invalid. """ 189 unique_people = models.ManyToManyField(Person, unique=True) 190 191 class NonUniqueFKTarget1(models.Model): 192 """ Model to test for non-unique FK target in yet-to-be-defined model: expect an error """ 193 tgt = models.ForeignKey('FKTarget', to_field='bad') 194 195 class UniqueFKTarget1(models.Model): 196 """ Model to test for unique FK target in yet-to-be-defined model: expect no error """ 197 tgt = models.ForeignKey('FKTarget', to_field='good') 198 199 class FKTarget(models.Model): 200 bad = models.IntegerField() 201 good = models.IntegerField(unique=True) 202 203 class NonUniqueFKTarget2(models.Model): 204 """ Model to test for non-unique FK target in previously seen model: expect an error """ 205 tgt = models.ForeignKey(FKTarget, to_field='bad') 206 207 class UniqueFKTarget2(models.Model): 208 """ Model to test for unique FK target in previously seen model: expect no error """ 209 tgt = models.ForeignKey(FKTarget, to_field='good') 210 211 class NonExistingOrderingWithSingleUnderscore(models.Model): 212 class Meta: 213 ordering = ("does_not_exist",) 214 215 class InvalidSetNull(models.Model): 216 fk = models.ForeignKey('self', on_delete=models.SET_NULL) 217 218 class InvalidSetDefault(models.Model): 219 fk = models.ForeignKey('self', on_delete=models.SET_DEFAULT) 220 221 model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer. 222 invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer. 223 invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer. 224 invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute that is a non-negative integer. 225 invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute that is a positive integer. 226 invalid_models.fielderrors: "decimalfield2": DecimalFields require a "decimal_places" attribute that is a non-negative integer. 227 invalid_models.fielderrors: "decimalfield2": DecimalFields require a "max_digits" attribute that is a positive integer. 228 invalid_models.fielderrors: "decimalfield3": DecimalFields require a "decimal_places" attribute that is a non-negative integer. 229 invalid_models.fielderrors: "decimalfield3": DecimalFields require a "max_digits" attribute that is a positive integer. 230 invalid_models.fielderrors: "decimalfield4": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute. 231 invalid_models.fielderrors: "decimalfield5": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute. 232 invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute. 233 invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list). 234 invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples. 235 invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples. 236 invalid_models.fielderrors: "index": "db_index" should be either None, True or False. 237 invalid_models.fielderrors: "field_": Field names cannot end with underscores, because this would lead to ambiguous queryset filters. 238 invalid_models.fielderrors: "nullbool": BooleanFields do not accept null values. Use a NullBooleanField instead. 239 invalid_models.clash1: Accessor for field 'foreign' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'. 240 invalid_models.clash1: Accessor for field 'foreign' clashes with related m2m field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'. 241 invalid_models.clash1: Reverse query name for field 'foreign' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'foreign'. 242 invalid_models.clash1: Accessor for m2m field 'm2m' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'. 243 invalid_models.clash1: Accessor for m2m field 'm2m' clashes with related field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'. 244 invalid_models.clash1: Reverse query name for m2m field 'm2m' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'm2m'. 245 invalid_models.clash2: Accessor for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'. 246 invalid_models.clash2: Accessor for field 'foreign_1' clashes with related m2m field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'. 247 invalid_models.clash2: Reverse query name for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'. 248 invalid_models.clash2: Reverse query name for field 'foreign_1' clashes with related m2m field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'. 249 invalid_models.clash2: Accessor for field 'foreign_2' clashes with related m2m field 'Target.src_safe'. Add a related_name argument to the definition for 'foreign_2'. 250 invalid_models.clash2: Reverse query name for field 'foreign_2' clashes with related m2m field 'Target.src_safe'. Add a related_name argument to the definition for 'foreign_2'. 251 invalid_models.clash2: Accessor for m2m field 'm2m_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'. 252 invalid_models.clash2: Accessor for m2m field 'm2m_1' clashes with related field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'. 253 invalid_models.clash2: Reverse query name for m2m field 'm2m_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'. 254 invalid_models.clash2: Reverse query name for m2m field 'm2m_1' clashes with related field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'. 255 invalid_models.clash2: Accessor for m2m field 'm2m_2' clashes with related field 'Target.src_safe'. Add a related_name argument to the definition for 'm2m_2'. 256 invalid_models.clash2: Reverse query name for m2m field 'm2m_2' clashes with related field 'Target.src_safe'. Add a related_name argument to the definition for 'm2m_2'. 257 invalid_models.clash3: Accessor for field 'foreign_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'. 258 invalid_models.clash3: Accessor for field 'foreign_1' clashes with related m2m field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'. 259 invalid_models.clash3: Reverse query name for field 'foreign_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'. 260 invalid_models.clash3: Reverse query name for field 'foreign_1' clashes with related m2m field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'. 261 invalid_models.clash3: Accessor for field 'foreign_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'. 262 invalid_models.clash3: Accessor for field 'foreign_2' clashes with related m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'. 263 invalid_models.clash3: Reverse query name for field 'foreign_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'. 264 invalid_models.clash3: Reverse query name for field 'foreign_2' clashes with related m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'. 265 invalid_models.clash3: Accessor for m2m field 'm2m_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'. 266 invalid_models.clash3: Accessor for m2m field 'm2m_1' clashes with related field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'. 267 invalid_models.clash3: Reverse query name for m2m field 'm2m_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'. 268 invalid_models.clash3: Reverse query name for m2m field 'm2m_1' clashes with related field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'. 269 invalid_models.clash3: Accessor for m2m field 'm2m_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'. 270 invalid_models.clash3: Accessor for m2m field 'm2m_2' clashes with related field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'. 271 invalid_models.clash3: Reverse query name for m2m field 'm2m_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'. 272 invalid_models.clash3: Reverse query name for m2m field 'm2m_2' clashes with related field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'. 273 invalid_models.clashforeign: Accessor for field 'foreign' clashes with field 'Target2.clashforeign_set'. Add a related_name argument to the definition for 'foreign'. 274 invalid_models.clashm2m: Accessor for m2m field 'm2m' clashes with m2m field 'Target2.clashm2m_set'. Add a related_name argument to the definition for 'm2m'. 275 invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'. 276 invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'. 277 invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'. 278 invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'. 279 invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'. 280 invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'. 281 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. 282 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. 283 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. 284 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. 285 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. 286 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. 287 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. 288 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. 289 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. 290 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. 291 invalid_models.selfclashforeign: Accessor for field 'selfclashforeign_set' clashes with field 'SelfClashForeign.selfclashforeign_set'. Add a related_name argument to the definition for 'selfclashforeign_set'. 292 invalid_models.selfclashforeign: Reverse query name for field 'selfclashforeign_set' clashes with field 'SelfClashForeign.selfclashforeign'. Add a related_name argument to the definition for 'selfclashforeign_set'. 293 invalid_models.selfclashforeign: Accessor for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'. 294 invalid_models.selfclashforeign: Reverse query name for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'. 295 invalid_models.selfclashforeign: Accessor for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'. 296 invalid_models.selfclashforeign: Reverse query name for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'. 297 invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'. 298 invalid_models.selfclashm2m: Reverse query name for m2m field 'selfclashm2m_set' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'selfclashm2m_set'. 299 invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'. 300 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. 301 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. 302 invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. 303 invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. 304 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. 305 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. 306 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. 307 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. 308 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. 309 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. 310 invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'. 311 invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'. 312 invalid_models.missingrelations: 'rel1' has a relation with model Rel1, which has either not been installed or is abstract. 313 invalid_models.missingrelations: 'rel2' has an m2m relation with model Rel2, which has either not been installed or is abstract. 314 invalid_models.grouptwo: 'primary' is a manually-defined m2m relation through model Membership, which does not have foreign keys to Person and GroupTwo 315 invalid_models.grouptwo: 'secondary' is a manually-defined m2m relation through model MembershipMissingFK, which does not have foreign keys to Group and GroupTwo 316 invalid_models.missingmanualm2mmodel: 'missing_m2m' specifies an m2m relation through model MissingM2MModel, which has not been installed 317 invalid_models.group: The model Group has two manually-defined m2m relations through the model Membership, which is not permitted. Please consider using an extra field on your intermediary model instead. 318 invalid_models.group: Intermediary model RelationshipDoubleFK has more than one foreign key to Person, which is ambiguous and is not permitted. 319 invalid_models.personselfrefm2m: Many-to-many fields with intermediate tables cannot be symmetrical. 320 invalid_models.personselfrefm2m: Intermediary model RelationshipTripleFK has more than two foreign keys to PersonSelfRefM2M, which is ambiguous and is not permitted. 321 invalid_models.personselfrefm2mexplicit: Many-to-many fields with intermediate tables cannot be symmetrical. 322 invalid_models.abstractrelationmodel: 'fk1' has a relation with model AbstractModel, which has either not been installed or is abstract. 323 invalid_models.abstractrelationmodel: 'fk2' has an m2m relation with model AbstractModel, which has either not been installed or is abstract. 324 invalid_models.uniquem2m: ManyToManyFields cannot be unique. Remove the unique argument on 'unique_people'. 325 invalid_models.nonuniquefktarget1: Field 'bad' under model 'FKTarget' must have a unique=True constraint. 326 invalid_models.nonuniquefktarget2: Field 'bad' under model 'FKTarget' must have a unique=True constraint. 327 invalid_models.nonexistingorderingwithsingleunderscore: "ordering" refers to "does_not_exist", a field that doesn't exist. 328 invalid_models.invalidsetnull: 'fk' specifies on_delete=SET_NULL, but cannot be null. 329 invalid_models.invalidsetdefault: 'fk' specifies on_delete=SET_DEFAULT, but has no default value. 330 """ -
tests/modeltests/invalid_models/models.py
diff -r 9a1f08c480bf tests/modeltests/invalid_models/models.py
a b 1 """2 26. Invalid models3 4 This example exists purely to point out errors in models.5 """6 7 from django.db import models8 9 class FieldErrors(models.Model):10 charfield = models.CharField()11 charfield2 = models.CharField(max_length=-1)12 charfield3 = models.CharField(max_length="bad")13 decimalfield = models.DecimalField()14 decimalfield2 = models.DecimalField(max_digits=-1, decimal_places=-1)15 decimalfield3 = models.DecimalField(max_digits="bad", decimal_places="bad")16 decimalfield4 = models.DecimalField(max_digits=9, decimal_places=10)17 decimalfield5 = models.DecimalField(max_digits=10, decimal_places=10)18 filefield = models.FileField()19 choices = models.CharField(max_length=10, choices='bad')20 choices2 = models.CharField(max_length=10, choices=[(1,2,3),(1,2,3)])21 index = models.CharField(max_length=10, db_index='bad')22 field_ = models.CharField(max_length=10)23 nullbool = models.BooleanField(null=True)24 25 class Target(models.Model):26 tgt_safe = models.CharField(max_length=10)27 clash1 = models.CharField(max_length=10)28 clash2 = models.CharField(max_length=10)29 30 clash1_set = models.CharField(max_length=10)31 32 class Clash1(models.Model):33 src_safe = models.CharField(max_length=10)34 35 foreign = models.ForeignKey(Target)36 m2m = models.ManyToManyField(Target)37 38 class Clash2(models.Model):39 src_safe = models.CharField(max_length=10)40 41 foreign_1 = models.ForeignKey(Target, related_name='id')42 foreign_2 = models.ForeignKey(Target, related_name='src_safe')43 44 m2m_1 = models.ManyToManyField(Target, related_name='id')45 m2m_2 = models.ManyToManyField(Target, related_name='src_safe')46 47 class Target2(models.Model):48 clash3 = models.CharField(max_length=10)49 foreign_tgt = models.ForeignKey(Target)50 clashforeign_set = models.ForeignKey(Target)51 52 m2m_tgt = models.ManyToManyField(Target)53 clashm2m_set = models.ManyToManyField(Target)54 55 class Clash3(models.Model):56 src_safe = models.CharField(max_length=10)57 58 foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt')59 foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt')60 61 m2m_1 = models.ManyToManyField(Target2, related_name='foreign_tgt')62 m2m_2 = models.ManyToManyField(Target2, related_name='m2m_tgt')63 64 class ClashForeign(models.Model):65 foreign = models.ForeignKey(Target2)66 67 class ClashM2M(models.Model):68 m2m = models.ManyToManyField(Target2)69 70 class SelfClashForeign(models.Model):71 src_safe = models.CharField(max_length=10)72 selfclashforeign = models.CharField(max_length=10)73 74 selfclashforeign_set = models.ForeignKey("SelfClashForeign")75 foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id')76 foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe')77 78 class ValidM2M(models.Model):79 src_safe = models.CharField(max_length=10)80 validm2m = models.CharField(max_length=10)81 82 # M2M fields are symmetrical by default. Symmetrical M2M fields83 # on self don't require a related accessor, so many potential84 # clashes are avoided.85 validm2m_set = models.ManyToManyField("self")86 87 m2m_1 = models.ManyToManyField("self", related_name='id')88 m2m_2 = models.ManyToManyField("self", related_name='src_safe')89 90 m2m_3 = models.ManyToManyField('self')91 m2m_4 = models.ManyToManyField('self')92 93 class SelfClashM2M(models.Model):94 src_safe = models.CharField(max_length=10)95 selfclashm2m = models.CharField(max_length=10)96 97 # Non-symmetrical M2M fields _do_ have related accessors, so98 # there is potential for clashes.99 selfclashm2m_set = models.ManyToManyField("self", symmetrical=False)100 101 m2m_1 = models.ManyToManyField("self", related_name='id', symmetrical=False)102 m2m_2 = models.ManyToManyField("self", related_name='src_safe', symmetrical=False)103 104 m2m_3 = models.ManyToManyField('self', symmetrical=False)105 m2m_4 = models.ManyToManyField('self', symmetrical=False)106 107 class Model(models.Model):108 "But it's valid to call a model Model."109 year = models.PositiveIntegerField() #1960110 make = models.CharField(max_length=10) #Aston Martin111 name = models.CharField(max_length=10) #DB 4 GT112 113 class Car(models.Model):114 colour = models.CharField(max_length=5)115 model = models.ForeignKey(Model)116 117 class MissingRelations(models.Model):118 rel1 = models.ForeignKey("Rel1")119 rel2 = models.ManyToManyField("Rel2")120 121 class MissingManualM2MModel(models.Model):122 name = models.CharField(max_length=5)123 missing_m2m = models.ManyToManyField(Model, through="MissingM2MModel")124 125 class Person(models.Model):126 name = models.CharField(max_length=5)127 128 class Group(models.Model):129 name = models.CharField(max_length=5)130 primary = models.ManyToManyField(Person, through="Membership", related_name="primary")131 secondary = models.ManyToManyField(Person, through="Membership", related_name="secondary")132 tertiary = models.ManyToManyField(Person, through="RelationshipDoubleFK", related_name="tertiary")133 134 class GroupTwo(models.Model):135 name = models.CharField(max_length=5)136 primary = models.ManyToManyField(Person, through="Membership")137 secondary = models.ManyToManyField(Group, through="MembershipMissingFK")138 139 class Membership(models.Model):140 person = models.ForeignKey(Person)141 group = models.ForeignKey(Group)142 not_default_or_null = models.CharField(max_length=5)143 144 class MembershipMissingFK(models.Model):145 person = models.ForeignKey(Person)146 147 class PersonSelfRefM2M(models.Model):148 name = models.CharField(max_length=5)149 friends = models.ManyToManyField('self', through="Relationship")150 too_many_friends = models.ManyToManyField('self', through="RelationshipTripleFK")151 152 class PersonSelfRefM2MExplicit(models.Model):153 name = models.CharField(max_length=5)154 friends = models.ManyToManyField('self', through="ExplicitRelationship", symmetrical=True)155 156 class Relationship(models.Model):157 first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set")158 second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set")159 date_added = models.DateTimeField()160 161 class ExplicitRelationship(models.Model):162 first = models.ForeignKey(PersonSelfRefM2MExplicit, related_name="rel_from_set")163 second = models.ForeignKey(PersonSelfRefM2MExplicit, related_name="rel_to_set")164 date_added = models.DateTimeField()165 166 class RelationshipTripleFK(models.Model):167 first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set_2")168 second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set_2")169 third = models.ForeignKey(PersonSelfRefM2M, related_name="too_many_by_far")170 date_added = models.DateTimeField()171 172 class RelationshipDoubleFK(models.Model):173 first = models.ForeignKey(Person, related_name="first_related_name")174 second = models.ForeignKey(Person, related_name="second_related_name")175 third = models.ForeignKey(Group, related_name="rel_to_set")176 date_added = models.DateTimeField()177 178 class AbstractModel(models.Model):179 name = models.CharField(max_length=10)180 class Meta:181 abstract = True182 183 class AbstractRelationModel(models.Model):184 fk1 = models.ForeignKey('AbstractModel')185 fk2 = models.ManyToManyField('AbstractModel')186 187 class UniqueM2M(models.Model):188 """ Model to test for unique ManyToManyFields, which are invalid. """189 unique_people = models.ManyToManyField(Person, unique=True)190 191 class NonUniqueFKTarget1(models.Model):192 """ Model to test for non-unique FK target in yet-to-be-defined model: expect an error """193 tgt = models.ForeignKey('FKTarget', to_field='bad')194 195 class UniqueFKTarget1(models.Model):196 """ Model to test for unique FK target in yet-to-be-defined model: expect no error """197 tgt = models.ForeignKey('FKTarget', to_field='good')198 199 class FKTarget(models.Model):200 bad = models.IntegerField()201 good = models.IntegerField(unique=True)202 203 class NonUniqueFKTarget2(models.Model):204 """ Model to test for non-unique FK target in previously seen model: expect an error """205 tgt = models.ForeignKey(FKTarget, to_field='bad')206 207 class UniqueFKTarget2(models.Model):208 """ Model to test for unique FK target in previously seen model: expect no error """209 tgt = models.ForeignKey(FKTarget, to_field='good')210 211 class NonExistingOrderingWithSingleUnderscore(models.Model):212 class Meta:213 ordering = ("does_not_exist",)214 215 class InvalidSetNull(models.Model):216 fk = models.ForeignKey('self', on_delete=models.SET_NULL)217 218 class InvalidSetDefault(models.Model):219 fk = models.ForeignKey('self', on_delete=models.SET_DEFAULT)220 221 model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer.222 invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer.223 invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer.224 invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute that is a non-negative integer.225 invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute that is a positive integer.226 invalid_models.fielderrors: "decimalfield2": DecimalFields require a "decimal_places" attribute that is a non-negative integer.227 invalid_models.fielderrors: "decimalfield2": DecimalFields require a "max_digits" attribute that is a positive integer.228 invalid_models.fielderrors: "decimalfield3": DecimalFields require a "decimal_places" attribute that is a non-negative integer.229 invalid_models.fielderrors: "decimalfield3": DecimalFields require a "max_digits" attribute that is a positive integer.230 invalid_models.fielderrors: "decimalfield4": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.231 invalid_models.fielderrors: "decimalfield5": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.232 invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.233 invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).234 invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.235 invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.236 invalid_models.fielderrors: "index": "db_index" should be either None, True or False.237 invalid_models.fielderrors: "field_": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.238 invalid_models.fielderrors: "nullbool": BooleanFields do not accept null values. Use a NullBooleanField instead.239 invalid_models.clash1: Accessor for field 'foreign' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.240 invalid_models.clash1: Accessor for field 'foreign' clashes with related m2m field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.241 invalid_models.clash1: Reverse query name for field 'foreign' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'foreign'.242 invalid_models.clash1: Accessor for m2m field 'm2m' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'.243 invalid_models.clash1: Accessor for m2m field 'm2m' clashes with related field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'.244 invalid_models.clash1: Reverse query name for m2m field 'm2m' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'm2m'.245 invalid_models.clash2: Accessor for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.246 invalid_models.clash2: Accessor for field 'foreign_1' clashes with related m2m field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.247 invalid_models.clash2: Reverse query name for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.248 invalid_models.clash2: Reverse query name for field 'foreign_1' clashes with related m2m field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.249 invalid_models.clash2: Accessor for field 'foreign_2' clashes with related m2m field 'Target.src_safe'. Add a related_name argument to the definition for 'foreign_2'.250 invalid_models.clash2: Reverse query name for field 'foreign_2' clashes with related m2m field 'Target.src_safe'. Add a related_name argument to the definition for 'foreign_2'.251 invalid_models.clash2: Accessor for m2m field 'm2m_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'.252 invalid_models.clash2: Accessor for m2m field 'm2m_1' clashes with related field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'.253 invalid_models.clash2: Reverse query name for m2m field 'm2m_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'.254 invalid_models.clash2: Reverse query name for m2m field 'm2m_1' clashes with related field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'.255 invalid_models.clash2: Accessor for m2m field 'm2m_2' clashes with related field 'Target.src_safe'. Add a related_name argument to the definition for 'm2m_2'.256 invalid_models.clash2: Reverse query name for m2m field 'm2m_2' clashes with related field 'Target.src_safe'. Add a related_name argument to the definition for 'm2m_2'.257 invalid_models.clash3: Accessor for field 'foreign_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'.258 invalid_models.clash3: Accessor for field 'foreign_1' clashes with related m2m field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'.259 invalid_models.clash3: Reverse query name for field 'foreign_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'.260 invalid_models.clash3: Reverse query name for field 'foreign_1' clashes with related m2m field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'.261 invalid_models.clash3: Accessor for field 'foreign_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'.262 invalid_models.clash3: Accessor for field 'foreign_2' clashes with related m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'.263 invalid_models.clash3: Reverse query name for field 'foreign_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'.264 invalid_models.clash3: Reverse query name for field 'foreign_2' clashes with related m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'.265 invalid_models.clash3: Accessor for m2m field 'm2m_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'.266 invalid_models.clash3: Accessor for m2m field 'm2m_1' clashes with related field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'.267 invalid_models.clash3: Reverse query name for m2m field 'm2m_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'.268 invalid_models.clash3: Reverse query name for m2m field 'm2m_1' clashes with related field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'.269 invalid_models.clash3: Accessor for m2m field 'm2m_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'.270 invalid_models.clash3: Accessor for m2m field 'm2m_2' clashes with related field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'.271 invalid_models.clash3: Reverse query name for m2m field 'm2m_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'.272 invalid_models.clash3: Reverse query name for m2m field 'm2m_2' clashes with related field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'.273 invalid_models.clashforeign: Accessor for field 'foreign' clashes with field 'Target2.clashforeign_set'. Add a related_name argument to the definition for 'foreign'.274 invalid_models.clashm2m: Accessor for m2m field 'm2m' clashes with m2m field 'Target2.clashm2m_set'. Add a related_name argument to the definition for 'm2m'.275 invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'.276 invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'.277 invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'.278 invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'.279 invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'.280 invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'.281 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.282 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.283 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.284 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.285 invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.286 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.287 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.288 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.289 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.290 invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.291 invalid_models.selfclashforeign: Accessor for field 'selfclashforeign_set' clashes with field 'SelfClashForeign.selfclashforeign_set'. Add a related_name argument to the definition for 'selfclashforeign_set'.292 invalid_models.selfclashforeign: Reverse query name for field 'selfclashforeign_set' clashes with field 'SelfClashForeign.selfclashforeign'. Add a related_name argument to the definition for 'selfclashforeign_set'.293 invalid_models.selfclashforeign: Accessor for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'.294 invalid_models.selfclashforeign: Reverse query name for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'.295 invalid_models.selfclashforeign: Accessor for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'.296 invalid_models.selfclashforeign: Reverse query name for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'.297 invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'.298 invalid_models.selfclashm2m: Reverse query name for m2m field 'selfclashm2m_set' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'selfclashm2m_set'.299 invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'.300 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'.301 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'.302 invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'.303 invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'.304 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'.305 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'.306 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'.307 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.308 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.309 invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.310 invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'.311 invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'.312 invalid_models.missingrelations: 'rel1' has a relation with model Rel1, which has either not been installed or is abstract.313 invalid_models.missingrelations: 'rel2' has an m2m relation with model Rel2, which has either not been installed or is abstract.314 invalid_models.grouptwo: 'primary' is a manually-defined m2m relation through model Membership, which does not have foreign keys to Person and GroupTwo315 invalid_models.grouptwo: 'secondary' is a manually-defined m2m relation through model MembershipMissingFK, which does not have foreign keys to Group and GroupTwo316 invalid_models.missingmanualm2mmodel: 'missing_m2m' specifies an m2m relation through model MissingM2MModel, which has not been installed317 invalid_models.group: The model Group has two manually-defined m2m relations through the model Membership, which is not permitted. Please consider using an extra field on your intermediary model instead.318 invalid_models.group: Intermediary model RelationshipDoubleFK has more than one foreign key to Person, which is ambiguous and is not permitted.319 invalid_models.personselfrefm2m: Many-to-many fields with intermediate tables cannot be symmetrical.320 invalid_models.personselfrefm2m: Intermediary model RelationshipTripleFK has more than two foreign keys to PersonSelfRefM2M, which is ambiguous and is not permitted.321 invalid_models.personselfrefm2mexplicit: Many-to-many fields with intermediate tables cannot be symmetrical.322 invalid_models.abstractrelationmodel: 'fk1' has a relation with model AbstractModel, which has either not been installed or is abstract.323 invalid_models.abstractrelationmodel: 'fk2' has an m2m relation with model AbstractModel, which has either not been installed or is abstract.324 invalid_models.uniquem2m: ManyToManyFields cannot be unique. Remove the unique argument on 'unique_people'.325 invalid_models.nonuniquefktarget1: Field 'bad' under model 'FKTarget' must have a unique=True constraint.326 invalid_models.nonuniquefktarget2: Field 'bad' under model 'FKTarget' must have a unique=True constraint.327 invalid_models.nonexistingorderingwithsingleunderscore: "ordering" refers to "does_not_exist", a field that doesn't exist.328 invalid_models.invalidsetnull: 'fk' specifies on_delete=SET_NULL, but cannot be null.329 invalid_models.invalidsetdefault: 'fk' specifies on_delete=SET_DEFAULT, but has no default value.330 """ -
new file tests/modeltests/invalid_models/tests.py
diff -r 9a1f08c480bf tests/modeltests/invalid_models/tests.py
- + 1 import sys 2 3 from django.utils import unittest 4 5 6 class InvalidModelTestCase(unittest.TestCase): 7 """Import an appliation with invalid models and test the exceptions.""" 8 9 def test_invalid_models(self): 10 from django.core.management.validation import get_validation_errors 11 from django.db.models.loading import load_app 12 from cStringIO import StringIO 13 14 try: 15 module = load_app("modeltests.invalid_models.invalid_models") 16 except Exception, e: 17 self.fail('Unable to load invalid model module') 18 19 # Make sure sys.stdout is not a tty so that we get errors without 20 # coloring attached (makes matching the results easier). We restore 21 # sys.stderr afterwards. 22 orig_stdout = sys.stdout 23 s = StringIO() 24 sys.stdout = s 25 count = get_validation_errors(s, module) 26 sys.stdout = orig_stdout 27 s.seek(0) 28 error_log = s.read() 29 actual = error_log.split('\n') 30 expected = module.model_errors.split('\n') 31 32 unexpected = [err for err in actual if err not in expected] 33 missing = [err for err in expected if err not in actual] 34 self.assertFalse(unexpected, "Unexpected Errors: " + '\n'.join(unexpected)) 35 self.assertFalse(missing, "Missing Errors: " + '\n'.join(missing)) 36 37 -
tests/runtests.py
diff -r 9a1f08c480bf tests/runtests.py
a b 6 6 import tempfile 7 7 8 8 import django.contrib as contrib 9 from django.utils import unittest10 9 11 10 CONTRIB_DIR_NAME = 'django.contrib' 12 11 MODEL_TESTS_DIR_NAME = 'modeltests' … … 50 49 modules = [] 51 50 for loc, dirpath in (MODEL_TESTS_DIR_NAME, MODEL_TEST_DIR), (REGRESSION_TESTS_DIR_NAME, REGRESSION_TEST_DIR), (CONTRIB_DIR_NAME, CONTRIB_DIR): 52 51 for f in os.listdir(dirpath): 53 if f.startswith('__init__') or f.startswith('.') or \ 54 f.startswith('sql') or f.startswith('invalid') or \ 55 os.path.basename(f) in REGRESSION_SUBDIRS_TO_SKIP: 52 if (f.startswith('__init__') or 53 f.startswith('.') or 54 f.startswith('sql') or 55 os.path.basename(f) in REGRESSION_SUBDIRS_TO_SKIP): 56 56 continue 57 57 modules.append((loc, f)) 58 58 return modules 59 59 60 def get_invalid_modules():61 modules = []62 for loc, dirpath in (MODEL_TESTS_DIR_NAME, MODEL_TEST_DIR), (REGRESSION_TESTS_DIR_NAME, REGRESSION_TEST_DIR), (CONTRIB_DIR_NAME, CONTRIB_DIR):63 for f in os.listdir(dirpath):64 if f.startswith('__init__') or f.startswith('.') or f.startswith('sql'):65 continue66 if f.startswith('invalid'):67 modules.append((loc, f))68 return modules69 70 class InvalidModelTestCase(unittest.TestCase):71 def __init__(self, module_label):72 unittest.TestCase.__init__(self)73 self.module_label = module_label74 75 def runTest(self):76 from django.core.management.validation import get_validation_errors77 from django.db.models.loading import load_app78 from cStringIO import StringIO79 80 try:81 module = load_app(self.module_label)82 except Exception, e:83 self.fail('Unable to load invalid model module')84 85 # Make sure sys.stdout is not a tty so that we get errors without86 # coloring attached (makes matching the results easier). We restore87 # sys.stderr afterwards.88 orig_stdout = sys.stdout89 s = StringIO()90 sys.stdout = s91 count = get_validation_errors(s, module)92 sys.stdout = orig_stdout93 s.seek(0)94 error_log = s.read()95 actual = error_log.split('\n')96 expected = module.model_errors.split('\n')97 98 unexpected = [err for err in actual if err not in expected]99 missing = [err for err in expected if err not in actual]100 101 self.assertTrue(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected))102 self.assertTrue(not missing, "Missing Errors: " + '\n'.join(missing))103 104 60 def setup(verbosity, test_labels): 105 61 from django.conf import settings 106 62 state = { … … 178 134 def django_tests(verbosity, interactive, failfast, test_labels): 179 135 from django.conf import settings 180 136 state = setup(verbosity, test_labels) 181 182 # Add tests for invalid models apps.183 137 extra_tests = [] 184 for module_dir, module_name in get_invalid_modules():185 module_label = '.'.join([module_dir, module_name])186 if not test_labels or module_name in test_labels:187 extra_tests.append(InvalidModelTestCase(module_label))188 try:189 # Invalid models are not working apps, so we cannot pass them into190 # the test runner with the other test_labels191 test_labels.remove(module_name)192 except ValueError:193 pass194 138 195 139 # If GeoDjango is used, add it's tests that aren't a part of 196 140 # an application (e.g., GEOS, GDAL, Distance objects).