Code

Ticket #16681: django-invalid-model-tests.diff

File django-invalid-model-tests.diff, 56.2 KB (added by anthonyb, 3 years ago)

Patch to fix invalid_models and streamline runtests.py

Line 
1diff -r 9a1f08c480bf tests/modeltests/invalid_models/invalid_models/models.py
2--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
3+++ b/tests/modeltests/invalid_models/invalid_models/models.py  Tue Aug 23 13:57:45 2011 +1000
4@@ -0,0 +1,330 @@
5+"""
6+26. Invalid models
7+
8+This example exists purely to point out errors in models.
9+"""
10+
11+from django.db import models
12+
13+class FieldErrors(models.Model):
14+    charfield = models.CharField()
15+    charfield2 = models.CharField(max_length=-1)
16+    charfield3 = models.CharField(max_length="bad")
17+    decimalfield = models.DecimalField()
18+    decimalfield2 = models.DecimalField(max_digits=-1, decimal_places=-1)
19+    decimalfield3 = models.DecimalField(max_digits="bad", decimal_places="bad")
20+    decimalfield4 = models.DecimalField(max_digits=9, decimal_places=10)
21+    decimalfield5 = models.DecimalField(max_digits=10, decimal_places=10)
22+    filefield = models.FileField()
23+    choices = models.CharField(max_length=10, choices='bad')
24+    choices2 = models.CharField(max_length=10, choices=[(1,2,3),(1,2,3)])
25+    index = models.CharField(max_length=10, db_index='bad')
26+    field_ = models.CharField(max_length=10)
27+    nullbool = models.BooleanField(null=True)
28+
29+class Target(models.Model):
30+    tgt_safe = models.CharField(max_length=10)
31+    clash1 = models.CharField(max_length=10)
32+    clash2 = models.CharField(max_length=10)
33+
34+    clash1_set = models.CharField(max_length=10)
35+
36+class Clash1(models.Model):
37+    src_safe = models.CharField(max_length=10)
38+
39+    foreign = models.ForeignKey(Target)
40+    m2m = models.ManyToManyField(Target)
41+
42+class Clash2(models.Model):
43+    src_safe = models.CharField(max_length=10)
44+
45+    foreign_1 = models.ForeignKey(Target, related_name='id')
46+    foreign_2 = models.ForeignKey(Target, related_name='src_safe')
47+
48+    m2m_1 = models.ManyToManyField(Target, related_name='id')
49+    m2m_2 = models.ManyToManyField(Target, related_name='src_safe')
50+
51+class Target2(models.Model):
52+    clash3 = models.CharField(max_length=10)
53+    foreign_tgt = models.ForeignKey(Target)
54+    clashforeign_set = models.ForeignKey(Target)
55+
56+    m2m_tgt = models.ManyToManyField(Target)
57+    clashm2m_set = models.ManyToManyField(Target)
58+
59+class Clash3(models.Model):
60+    src_safe = models.CharField(max_length=10)
61+
62+    foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt')
63+    foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt')
64+
65+    m2m_1 = models.ManyToManyField(Target2, related_name='foreign_tgt')
66+    m2m_2 = models.ManyToManyField(Target2, related_name='m2m_tgt')
67+
68+class ClashForeign(models.Model):
69+    foreign = models.ForeignKey(Target2)
70+
71+class ClashM2M(models.Model):
72+    m2m = models.ManyToManyField(Target2)
73+
74+class SelfClashForeign(models.Model):
75+    src_safe = models.CharField(max_length=10)
76+    selfclashforeign = models.CharField(max_length=10)
77+
78+    selfclashforeign_set = models.ForeignKey("SelfClashForeign")
79+    foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id')
80+    foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe')
81+
82+class ValidM2M(models.Model):
83+    src_safe = models.CharField(max_length=10)
84+    validm2m = models.CharField(max_length=10)
85+
86+    # M2M fields are symmetrical by default. Symmetrical M2M fields
87+    # on self don't require a related accessor, so many potential
88+    # clashes are avoided.
89+    validm2m_set = models.ManyToManyField("self")
90+
91+    m2m_1 = models.ManyToManyField("self", related_name='id')
92+    m2m_2 = models.ManyToManyField("self", related_name='src_safe')
93+
94+    m2m_3 = models.ManyToManyField('self')
95+    m2m_4 = models.ManyToManyField('self')
96+
97+class SelfClashM2M(models.Model):
98+    src_safe = models.CharField(max_length=10)
99+    selfclashm2m = models.CharField(max_length=10)
100+
101+    # Non-symmetrical M2M fields _do_ have related accessors, so
102+    # there is potential for clashes.
103+    selfclashm2m_set = models.ManyToManyField("self", symmetrical=False)
104+
105+    m2m_1 = models.ManyToManyField("self", related_name='id', symmetrical=False)
106+    m2m_2 = models.ManyToManyField("self", related_name='src_safe', symmetrical=False)
107+
108+    m2m_3 = models.ManyToManyField('self', symmetrical=False)
109+    m2m_4 = models.ManyToManyField('self', symmetrical=False)
110+
111+class Model(models.Model):
112+    "But it's valid to call a model Model."
113+    year = models.PositiveIntegerField() #1960
114+    make = models.CharField(max_length=10) #Aston Martin
115+    name = models.CharField(max_length=10) #DB 4 GT
116+
117+class Car(models.Model):
118+    colour = models.CharField(max_length=5)
119+    model = models.ForeignKey(Model)
120+
121+class MissingRelations(models.Model):
122+    rel1 = models.ForeignKey("Rel1")
123+    rel2 = models.ManyToManyField("Rel2")
124+
125+class MissingManualM2MModel(models.Model):
126+    name = models.CharField(max_length=5)
127+    missing_m2m = models.ManyToManyField(Model, through="MissingM2MModel")
128+
129+class Person(models.Model):
130+    name = models.CharField(max_length=5)
131+
132+class Group(models.Model):
133+    name = models.CharField(max_length=5)
134+    primary = models.ManyToManyField(Person, through="Membership", related_name="primary")
135+    secondary = models.ManyToManyField(Person, through="Membership", related_name="secondary")
136+    tertiary = models.ManyToManyField(Person, through="RelationshipDoubleFK", related_name="tertiary")
137+
138+class GroupTwo(models.Model):
139+    name = models.CharField(max_length=5)
140+    primary = models.ManyToManyField(Person, through="Membership")
141+    secondary = models.ManyToManyField(Group, through="MembershipMissingFK")
142+
143+class Membership(models.Model):
144+    person = models.ForeignKey(Person)
145+    group = models.ForeignKey(Group)
146+    not_default_or_null = models.CharField(max_length=5)
147+
148+class MembershipMissingFK(models.Model):
149+    person = models.ForeignKey(Person)
150+
151+class PersonSelfRefM2M(models.Model):
152+    name = models.CharField(max_length=5)
153+    friends = models.ManyToManyField('self', through="Relationship")
154+    too_many_friends = models.ManyToManyField('self', through="RelationshipTripleFK")
155+
156+class PersonSelfRefM2MExplicit(models.Model):
157+    name = models.CharField(max_length=5)
158+    friends = models.ManyToManyField('self', through="ExplicitRelationship", symmetrical=True)
159+
160+class Relationship(models.Model):
161+    first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set")
162+    second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set")
163+    date_added = models.DateTimeField()
164+
165+class ExplicitRelationship(models.Model):
166+    first = models.ForeignKey(PersonSelfRefM2MExplicit, related_name="rel_from_set")
167+    second = models.ForeignKey(PersonSelfRefM2MExplicit, related_name="rel_to_set")
168+    date_added = models.DateTimeField()
169+
170+class RelationshipTripleFK(models.Model):
171+    first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set_2")
172+    second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set_2")
173+    third = models.ForeignKey(PersonSelfRefM2M, related_name="too_many_by_far")
174+    date_added = models.DateTimeField()
175+
176+class RelationshipDoubleFK(models.Model):
177+    first = models.ForeignKey(Person, related_name="first_related_name")
178+    second = models.ForeignKey(Person, related_name="second_related_name")
179+    third = models.ForeignKey(Group, related_name="rel_to_set")
180+    date_added = models.DateTimeField()
181+
182+class AbstractModel(models.Model):
183+    name = models.CharField(max_length=10)
184+    class Meta:
185+        abstract = True
186+
187+class AbstractRelationModel(models.Model):
188+    fk1 = models.ForeignKey('AbstractModel')
189+    fk2 = models.ManyToManyField('AbstractModel')
190+
191+class UniqueM2M(models.Model):
192+    """ Model to test for unique ManyToManyFields, which are invalid. """
193+    unique_people = models.ManyToManyField(Person, unique=True)
194+
195+class NonUniqueFKTarget1(models.Model):
196+    """ Model to test for non-unique FK target in yet-to-be-defined model: expect an error """
197+    tgt = models.ForeignKey('FKTarget', to_field='bad')
198+
199+class UniqueFKTarget1(models.Model):
200+    """ Model to test for unique FK target in yet-to-be-defined model: expect no error """
201+    tgt = models.ForeignKey('FKTarget', to_field='good')
202+
203+class FKTarget(models.Model):
204+    bad = models.IntegerField()
205+    good = models.IntegerField(unique=True)
206+
207+class NonUniqueFKTarget2(models.Model):
208+    """ Model to test for non-unique FK target in previously seen model: expect an error """
209+    tgt = models.ForeignKey(FKTarget, to_field='bad')
210+
211+class UniqueFKTarget2(models.Model):
212+    """ Model to test for unique FK target in previously seen model: expect no error """
213+    tgt = models.ForeignKey(FKTarget, to_field='good')
214+
215+class NonExistingOrderingWithSingleUnderscore(models.Model):
216+    class Meta:
217+        ordering = ("does_not_exist",)
218+
219+class InvalidSetNull(models.Model):
220+    fk = models.ForeignKey('self', on_delete=models.SET_NULL)
221+
222+class InvalidSetDefault(models.Model):
223+    fk = models.ForeignKey('self', on_delete=models.SET_DEFAULT)
224+
225+model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer.
226+invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer.
227+invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer.
228+invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute that is a non-negative integer.
229+invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute that is a positive integer.
230+invalid_models.fielderrors: "decimalfield2": DecimalFields require a "decimal_places" attribute that is a non-negative integer.
231+invalid_models.fielderrors: "decimalfield2": DecimalFields require a "max_digits" attribute that is a positive integer.
232+invalid_models.fielderrors: "decimalfield3": DecimalFields require a "decimal_places" attribute that is a non-negative integer.
233+invalid_models.fielderrors: "decimalfield3": DecimalFields require a "max_digits" attribute that is a positive integer.
234+invalid_models.fielderrors: "decimalfield4": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
235+invalid_models.fielderrors: "decimalfield5": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
236+invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
237+invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).
238+invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
239+invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
240+invalid_models.fielderrors: "index": "db_index" should be either None, True or False.
241+invalid_models.fielderrors: "field_": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.
242+invalid_models.fielderrors: "nullbool": BooleanFields do not accept null values. Use a NullBooleanField instead.
243+invalid_models.clash1: Accessor for field 'foreign' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.
244+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'.
245+invalid_models.clash1: Reverse query name for field 'foreign' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'foreign'.
246+invalid_models.clash1: Accessor for m2m field 'm2m' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'.
247+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'.
248+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'.
249+invalid_models.clash2: Accessor for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.
250+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'.
251+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'.
252+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'.
253+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'.
254+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'.
255+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'.
256+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'.
257+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'.
258+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'.
259+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'.
260+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'.
261+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'.
262+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'.
263+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'.
264+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'.
265+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'.
266+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'.
267+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'.
268+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'.
269+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'.
270+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'.
271+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'.
272+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'.
273+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'.
274+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'.
275+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'.
276+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'.
277+invalid_models.clashforeign: Accessor for field 'foreign' clashes with field 'Target2.clashforeign_set'. Add a related_name argument to the definition for 'foreign'.
278+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'.
279+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'.
280+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'.
281+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'.
282+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'.
283+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'.
284+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'.
285+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'.
286+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'.
287+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'.
288+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'.
289+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'.
290+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'.
291+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'.
292+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'.
293+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'.
294+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'.
295+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'.
296+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'.
297+invalid_models.selfclashforeign: Accessor for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'.
298+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'.
299+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'.
300+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'.
301+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'.
302+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'.
303+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'.
304+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'.
305+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'.
306+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'.
307+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'.
308+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'.
309+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'.
310+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'.
311+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'.
312+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'.
313+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'.
314+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'.
315+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'.
316+invalid_models.missingrelations: 'rel1' has a relation with model Rel1, which has either not been installed or is abstract.
317+invalid_models.missingrelations: 'rel2' has an m2m relation with model Rel2, which has either not been installed or is abstract.
318+invalid_models.grouptwo: 'primary' is a manually-defined m2m relation through model Membership, which does not have foreign keys to Person and GroupTwo
319+invalid_models.grouptwo: 'secondary' is a manually-defined m2m relation through model MembershipMissingFK, which does not have foreign keys to Group and GroupTwo
320+invalid_models.missingmanualm2mmodel: 'missing_m2m' specifies an m2m relation through model MissingM2MModel, which has not been installed
321+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.
322+invalid_models.group: Intermediary model RelationshipDoubleFK has more than one foreign key to Person, which is ambiguous and is not permitted.
323+invalid_models.personselfrefm2m: Many-to-many fields with intermediate tables cannot be symmetrical.
324+invalid_models.personselfrefm2m: Intermediary model RelationshipTripleFK has more than two foreign keys to PersonSelfRefM2M, which is ambiguous and is not permitted.
325+invalid_models.personselfrefm2mexplicit: Many-to-many fields with intermediate tables cannot be symmetrical.
326+invalid_models.abstractrelationmodel: 'fk1' has a relation with model AbstractModel, which has either not been installed or is abstract.
327+invalid_models.abstractrelationmodel: 'fk2' has an m2m relation with model AbstractModel, which has either not been installed or is abstract.
328+invalid_models.uniquem2m: ManyToManyFields cannot be unique.  Remove the unique argument on 'unique_people'.
329+invalid_models.nonuniquefktarget1: Field 'bad' under model 'FKTarget' must have a unique=True constraint.
330+invalid_models.nonuniquefktarget2: Field 'bad' under model 'FKTarget' must have a unique=True constraint.
331+invalid_models.nonexistingorderingwithsingleunderscore: "ordering" refers to "does_not_exist", a field that doesn't exist.
332+invalid_models.invalidsetnull: 'fk' specifies on_delete=SET_NULL, but cannot be null.
333+invalid_models.invalidsetdefault: 'fk' specifies on_delete=SET_DEFAULT, but has no default value.
334+"""
335diff -r 9a1f08c480bf tests/modeltests/invalid_models/models.py
336--- a/tests/modeltests/invalid_models/models.py Tue Aug 23 00:52:45 2011 +0000
337+++ b/tests/modeltests/invalid_models/models.py Tue Aug 23 13:57:45 2011 +1000
338@@ -1,330 +0,0 @@
339-"""
340-26. Invalid models
341-
342-This example exists purely to point out errors in models.
343-"""
344-
345-from django.db import models
346-
347-class FieldErrors(models.Model):
348-    charfield = models.CharField()
349-    charfield2 = models.CharField(max_length=-1)
350-    charfield3 = models.CharField(max_length="bad")
351-    decimalfield = models.DecimalField()
352-    decimalfield2 = models.DecimalField(max_digits=-1, decimal_places=-1)
353-    decimalfield3 = models.DecimalField(max_digits="bad", decimal_places="bad")
354-    decimalfield4 = models.DecimalField(max_digits=9, decimal_places=10)
355-    decimalfield5 = models.DecimalField(max_digits=10, decimal_places=10)
356-    filefield = models.FileField()
357-    choices = models.CharField(max_length=10, choices='bad')
358-    choices2 = models.CharField(max_length=10, choices=[(1,2,3),(1,2,3)])
359-    index = models.CharField(max_length=10, db_index='bad')
360-    field_ = models.CharField(max_length=10)
361-    nullbool = models.BooleanField(null=True)
362-
363-class Target(models.Model):
364-    tgt_safe = models.CharField(max_length=10)
365-    clash1 = models.CharField(max_length=10)
366-    clash2 = models.CharField(max_length=10)
367-
368-    clash1_set = models.CharField(max_length=10)
369-
370-class Clash1(models.Model):
371-    src_safe = models.CharField(max_length=10)
372-
373-    foreign = models.ForeignKey(Target)
374-    m2m = models.ManyToManyField(Target)
375-
376-class Clash2(models.Model):
377-    src_safe = models.CharField(max_length=10)
378-
379-    foreign_1 = models.ForeignKey(Target, related_name='id')
380-    foreign_2 = models.ForeignKey(Target, related_name='src_safe')
381-
382-    m2m_1 = models.ManyToManyField(Target, related_name='id')
383-    m2m_2 = models.ManyToManyField(Target, related_name='src_safe')
384-
385-class Target2(models.Model):
386-    clash3 = models.CharField(max_length=10)
387-    foreign_tgt = models.ForeignKey(Target)
388-    clashforeign_set = models.ForeignKey(Target)
389-
390-    m2m_tgt = models.ManyToManyField(Target)
391-    clashm2m_set = models.ManyToManyField(Target)
392-
393-class Clash3(models.Model):
394-    src_safe = models.CharField(max_length=10)
395-
396-    foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt')
397-    foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt')
398-
399-    m2m_1 = models.ManyToManyField(Target2, related_name='foreign_tgt')
400-    m2m_2 = models.ManyToManyField(Target2, related_name='m2m_tgt')
401-
402-class ClashForeign(models.Model):
403-    foreign = models.ForeignKey(Target2)
404-
405-class ClashM2M(models.Model):
406-    m2m = models.ManyToManyField(Target2)
407-
408-class SelfClashForeign(models.Model):
409-    src_safe = models.CharField(max_length=10)
410-    selfclashforeign = models.CharField(max_length=10)
411-
412-    selfclashforeign_set = models.ForeignKey("SelfClashForeign")
413-    foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id')
414-    foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe')
415-
416-class ValidM2M(models.Model):
417-    src_safe = models.CharField(max_length=10)
418-    validm2m = models.CharField(max_length=10)
419-
420-    # M2M fields are symmetrical by default. Symmetrical M2M fields
421-    # on self don't require a related accessor, so many potential
422-    # clashes are avoided.
423-    validm2m_set = models.ManyToManyField("self")
424-
425-    m2m_1 = models.ManyToManyField("self", related_name='id')
426-    m2m_2 = models.ManyToManyField("self", related_name='src_safe')
427-
428-    m2m_3 = models.ManyToManyField('self')
429-    m2m_4 = models.ManyToManyField('self')
430-
431-class SelfClashM2M(models.Model):
432-    src_safe = models.CharField(max_length=10)
433-    selfclashm2m = models.CharField(max_length=10)
434-
435-    # Non-symmetrical M2M fields _do_ have related accessors, so
436-    # there is potential for clashes.
437-    selfclashm2m_set = models.ManyToManyField("self", symmetrical=False)
438-
439-    m2m_1 = models.ManyToManyField("self", related_name='id', symmetrical=False)
440-    m2m_2 = models.ManyToManyField("self", related_name='src_safe', symmetrical=False)
441-
442-    m2m_3 = models.ManyToManyField('self', symmetrical=False)
443-    m2m_4 = models.ManyToManyField('self', symmetrical=False)
444-
445-class Model(models.Model):
446-    "But it's valid to call a model Model."
447-    year = models.PositiveIntegerField() #1960
448-    make = models.CharField(max_length=10) #Aston Martin
449-    name = models.CharField(max_length=10) #DB 4 GT
450-
451-class Car(models.Model):
452-    colour = models.CharField(max_length=5)
453-    model = models.ForeignKey(Model)
454-
455-class MissingRelations(models.Model):
456-    rel1 = models.ForeignKey("Rel1")
457-    rel2 = models.ManyToManyField("Rel2")
458-
459-class MissingManualM2MModel(models.Model):
460-    name = models.CharField(max_length=5)
461-    missing_m2m = models.ManyToManyField(Model, through="MissingM2MModel")
462-
463-class Person(models.Model):
464-    name = models.CharField(max_length=5)
465-
466-class Group(models.Model):
467-    name = models.CharField(max_length=5)
468-    primary = models.ManyToManyField(Person, through="Membership", related_name="primary")
469-    secondary = models.ManyToManyField(Person, through="Membership", related_name="secondary")
470-    tertiary = models.ManyToManyField(Person, through="RelationshipDoubleFK", related_name="tertiary")
471-
472-class GroupTwo(models.Model):
473-    name = models.CharField(max_length=5)
474-    primary = models.ManyToManyField(Person, through="Membership")
475-    secondary = models.ManyToManyField(Group, through="MembershipMissingFK")
476-
477-class Membership(models.Model):
478-    person = models.ForeignKey(Person)
479-    group = models.ForeignKey(Group)
480-    not_default_or_null = models.CharField(max_length=5)
481-
482-class MembershipMissingFK(models.Model):
483-    person = models.ForeignKey(Person)
484-
485-class PersonSelfRefM2M(models.Model):
486-    name = models.CharField(max_length=5)
487-    friends = models.ManyToManyField('self', through="Relationship")
488-    too_many_friends = models.ManyToManyField('self', through="RelationshipTripleFK")
489-
490-class PersonSelfRefM2MExplicit(models.Model):
491-    name = models.CharField(max_length=5)
492-    friends = models.ManyToManyField('self', through="ExplicitRelationship", symmetrical=True)
493-
494-class Relationship(models.Model):
495-    first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set")
496-    second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set")
497-    date_added = models.DateTimeField()
498-
499-class ExplicitRelationship(models.Model):
500-    first = models.ForeignKey(PersonSelfRefM2MExplicit, related_name="rel_from_set")
501-    second = models.ForeignKey(PersonSelfRefM2MExplicit, related_name="rel_to_set")
502-    date_added = models.DateTimeField()
503-
504-class RelationshipTripleFK(models.Model):
505-    first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set_2")
506-    second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set_2")
507-    third = models.ForeignKey(PersonSelfRefM2M, related_name="too_many_by_far")
508-    date_added = models.DateTimeField()
509-
510-class RelationshipDoubleFK(models.Model):
511-    first = models.ForeignKey(Person, related_name="first_related_name")
512-    second = models.ForeignKey(Person, related_name="second_related_name")
513-    third = models.ForeignKey(Group, related_name="rel_to_set")
514-    date_added = models.DateTimeField()
515-
516-class AbstractModel(models.Model):
517-    name = models.CharField(max_length=10)
518-    class Meta:
519-        abstract = True
520-
521-class AbstractRelationModel(models.Model):
522-    fk1 = models.ForeignKey('AbstractModel')
523-    fk2 = models.ManyToManyField('AbstractModel')
524-
525-class UniqueM2M(models.Model):
526-    """ Model to test for unique ManyToManyFields, which are invalid. """
527-    unique_people = models.ManyToManyField(Person, unique=True)
528-
529-class NonUniqueFKTarget1(models.Model):
530-    """ Model to test for non-unique FK target in yet-to-be-defined model: expect an error """
531-    tgt = models.ForeignKey('FKTarget', to_field='bad')
532-
533-class UniqueFKTarget1(models.Model):
534-    """ Model to test for unique FK target in yet-to-be-defined model: expect no error """
535-    tgt = models.ForeignKey('FKTarget', to_field='good')
536-
537-class FKTarget(models.Model):
538-    bad = models.IntegerField()
539-    good = models.IntegerField(unique=True)
540-
541-class NonUniqueFKTarget2(models.Model):
542-    """ Model to test for non-unique FK target in previously seen model: expect an error """
543-    tgt = models.ForeignKey(FKTarget, to_field='bad')
544-
545-class UniqueFKTarget2(models.Model):
546-    """ Model to test for unique FK target in previously seen model: expect no error """
547-    tgt = models.ForeignKey(FKTarget, to_field='good')
548-
549-class NonExistingOrderingWithSingleUnderscore(models.Model):
550-    class Meta:
551-        ordering = ("does_not_exist",)
552-
553-class InvalidSetNull(models.Model):
554-    fk = models.ForeignKey('self', on_delete=models.SET_NULL)
555-
556-class InvalidSetDefault(models.Model):
557-    fk = models.ForeignKey('self', on_delete=models.SET_DEFAULT)
558-
559-model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer.
560-invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer.
561-invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer.
562-invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute that is a non-negative integer.
563-invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute that is a positive integer.
564-invalid_models.fielderrors: "decimalfield2": DecimalFields require a "decimal_places" attribute that is a non-negative integer.
565-invalid_models.fielderrors: "decimalfield2": DecimalFields require a "max_digits" attribute that is a positive integer.
566-invalid_models.fielderrors: "decimalfield3": DecimalFields require a "decimal_places" attribute that is a non-negative integer.
567-invalid_models.fielderrors: "decimalfield3": DecimalFields require a "max_digits" attribute that is a positive integer.
568-invalid_models.fielderrors: "decimalfield4": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
569-invalid_models.fielderrors: "decimalfield5": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
570-invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
571-invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).
572-invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
573-invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
574-invalid_models.fielderrors: "index": "db_index" should be either None, True or False.
575-invalid_models.fielderrors: "field_": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.
576-invalid_models.fielderrors: "nullbool": BooleanFields do not accept null values. Use a NullBooleanField instead.
577-invalid_models.clash1: Accessor for field 'foreign' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.
578-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'.
579-invalid_models.clash1: Reverse query name for field 'foreign' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'foreign'.
580-invalid_models.clash1: Accessor for m2m field 'm2m' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'.
581-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'.
582-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'.
583-invalid_models.clash2: Accessor for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.
584-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'.
585-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'.
586-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'.
587-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'.
588-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'.
589-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'.
590-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'.
591-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'.
592-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'.
593-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'.
594-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'.
595-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'.
596-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'.
597-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'.
598-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'.
599-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'.
600-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'.
601-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'.
602-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'.
603-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'.
604-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'.
605-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'.
606-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'.
607-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'.
608-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'.
609-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'.
610-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'.
611-invalid_models.clashforeign: Accessor for field 'foreign' clashes with field 'Target2.clashforeign_set'. Add a related_name argument to the definition for 'foreign'.
612-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'.
613-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'.
614-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'.
615-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'.
616-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'.
617-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'.
618-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'.
619-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'.
620-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'.
621-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'.
622-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'.
623-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'.
624-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'.
625-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'.
626-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'.
627-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'.
628-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'.
629-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'.
630-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'.
631-invalid_models.selfclashforeign: Accessor for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'.
632-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'.
633-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'.
634-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'.
635-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'.
636-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'.
637-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'.
638-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'.
639-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'.
640-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'.
641-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'.
642-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'.
643-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'.
644-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'.
645-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'.
646-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'.
647-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'.
648-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'.
649-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'.
650-invalid_models.missingrelations: 'rel1' has a relation with model Rel1, which has either not been installed or is abstract.
651-invalid_models.missingrelations: 'rel2' has an m2m relation with model Rel2, which has either not been installed or is abstract.
652-invalid_models.grouptwo: 'primary' is a manually-defined m2m relation through model Membership, which does not have foreign keys to Person and GroupTwo
653-invalid_models.grouptwo: 'secondary' is a manually-defined m2m relation through model MembershipMissingFK, which does not have foreign keys to Group and GroupTwo
654-invalid_models.missingmanualm2mmodel: 'missing_m2m' specifies an m2m relation through model MissingM2MModel, which has not been installed
655-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.
656-invalid_models.group: Intermediary model RelationshipDoubleFK has more than one foreign key to Person, which is ambiguous and is not permitted.
657-invalid_models.personselfrefm2m: Many-to-many fields with intermediate tables cannot be symmetrical.
658-invalid_models.personselfrefm2m: Intermediary model RelationshipTripleFK has more than two foreign keys to PersonSelfRefM2M, which is ambiguous and is not permitted.
659-invalid_models.personselfrefm2mexplicit: Many-to-many fields with intermediate tables cannot be symmetrical.
660-invalid_models.abstractrelationmodel: 'fk1' has a relation with model AbstractModel, which has either not been installed or is abstract.
661-invalid_models.abstractrelationmodel: 'fk2' has an m2m relation with model AbstractModel, which has either not been installed or is abstract.
662-invalid_models.uniquem2m: ManyToManyFields cannot be unique.  Remove the unique argument on 'unique_people'.
663-invalid_models.nonuniquefktarget1: Field 'bad' under model 'FKTarget' must have a unique=True constraint.
664-invalid_models.nonuniquefktarget2: Field 'bad' under model 'FKTarget' must have a unique=True constraint.
665-invalid_models.nonexistingorderingwithsingleunderscore: "ordering" refers to "does_not_exist", a field that doesn't exist.
666-invalid_models.invalidsetnull: 'fk' specifies on_delete=SET_NULL, but cannot be null.
667-invalid_models.invalidsetdefault: 'fk' specifies on_delete=SET_DEFAULT, but has no default value.
668-"""
669diff -r 9a1f08c480bf tests/modeltests/invalid_models/tests.py
670--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
671+++ b/tests/modeltests/invalid_models/tests.py  Tue Aug 23 13:57:45 2011 +1000
672@@ -0,0 +1,37 @@
673+import sys
674+
675+from django.utils import unittest
676+
677+
678+class InvalidModelTestCase(unittest.TestCase):
679+    """Import an appliation with invalid models and test the exceptions."""
680+
681+    def test_invalid_models(self):
682+        from django.core.management.validation import get_validation_errors
683+        from django.db.models.loading import load_app
684+        from cStringIO import StringIO
685+       
686+        try:
687+            module = load_app("modeltests.invalid_models.invalid_models")
688+        except Exception, e:
689+            self.fail('Unable to load invalid model module')
690+       
691+        # Make sure sys.stdout is not a tty so that we get errors without
692+        # coloring attached (makes matching the results easier). We restore
693+        # sys.stderr afterwards.
694+        orig_stdout = sys.stdout
695+        s = StringIO()
696+        sys.stdout = s
697+        count = get_validation_errors(s, module)
698+        sys.stdout = orig_stdout
699+        s.seek(0)
700+        error_log = s.read()
701+        actual = error_log.split('\n')
702+        expected = module.model_errors.split('\n')
703+
704+        unexpected = [err for err in actual if err not in expected]
705+        missing = [err for err in expected if err not in actual]
706+        self.assertFalse(unexpected, "Unexpected Errors: " + '\n'.join(unexpected))
707+        self.assertFalse(missing, "Missing Errors: " + '\n'.join(missing))
708+
709+
710diff -r 9a1f08c480bf tests/runtests.py
711--- a/tests/runtests.py Tue Aug 23 00:52:45 2011 +0000
712+++ b/tests/runtests.py Tue Aug 23 13:57:45 2011 +1000
713@@ -6,7 +6,6 @@
714 import tempfile
715 
716 import django.contrib as contrib
717-from django.utils import unittest
718 
719 CONTRIB_DIR_NAME = 'django.contrib'
720 MODEL_TESTS_DIR_NAME = 'modeltests'
721@@ -50,57 +49,14 @@
722     modules = []
723     for loc, dirpath in (MODEL_TESTS_DIR_NAME, MODEL_TEST_DIR), (REGRESSION_TESTS_DIR_NAME, REGRESSION_TEST_DIR), (CONTRIB_DIR_NAME, CONTRIB_DIR):
724         for f in os.listdir(dirpath):
725-            if f.startswith('__init__') or f.startswith('.') or \
726-               f.startswith('sql') or f.startswith('invalid') or \
727-               os.path.basename(f) in REGRESSION_SUBDIRS_TO_SKIP:
728+            if (f.startswith('__init__') or
729+                f.startswith('.') or
730+                f.startswith('sql') or
731+                os.path.basename(f) in REGRESSION_SUBDIRS_TO_SKIP):
732                 continue
733             modules.append((loc, f))
734     return modules
735 
736-def get_invalid_modules():
737-    modules = []
738-    for loc, dirpath in (MODEL_TESTS_DIR_NAME, MODEL_TEST_DIR), (REGRESSION_TESTS_DIR_NAME, REGRESSION_TEST_DIR), (CONTRIB_DIR_NAME, CONTRIB_DIR):
739-        for f in os.listdir(dirpath):
740-            if f.startswith('__init__') or f.startswith('.') or f.startswith('sql'):
741-                continue
742-            if f.startswith('invalid'):
743-                modules.append((loc, f))
744-    return modules
745-
746-class InvalidModelTestCase(unittest.TestCase):
747-    def __init__(self, module_label):
748-        unittest.TestCase.__init__(self)
749-        self.module_label = module_label
750-
751-    def runTest(self):
752-        from django.core.management.validation import get_validation_errors
753-        from django.db.models.loading import load_app
754-        from cStringIO import StringIO
755-
756-        try:
757-            module = load_app(self.module_label)
758-        except Exception, e:
759-            self.fail('Unable to load invalid model module')
760-
761-        # Make sure sys.stdout is not a tty so that we get errors without
762-        # coloring attached (makes matching the results easier). We restore
763-        # sys.stderr afterwards.
764-        orig_stdout = sys.stdout
765-        s = StringIO()
766-        sys.stdout = s
767-        count = get_validation_errors(s, module)
768-        sys.stdout = orig_stdout
769-        s.seek(0)
770-        error_log = s.read()
771-        actual = error_log.split('\n')
772-        expected = module.model_errors.split('\n')
773-
774-        unexpected = [err for err in actual if err not in expected]
775-        missing = [err for err in expected if err not in actual]
776-
777-        self.assertTrue(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected))
778-        self.assertTrue(not missing, "Missing Errors: " + '\n'.join(missing))
779-
780 def setup(verbosity, test_labels):
781     from django.conf import settings
782     state = {
783@@ -178,19 +134,7 @@
784 def django_tests(verbosity, interactive, failfast, test_labels):
785     from django.conf import settings
786     state = setup(verbosity, test_labels)
787-
788-    # Add tests for invalid models apps.
789     extra_tests = []
790-    for module_dir, module_name in get_invalid_modules():
791-        module_label = '.'.join([module_dir, module_name])
792-        if not test_labels or module_name in test_labels:
793-            extra_tests.append(InvalidModelTestCase(module_label))
794-            try:
795-                # Invalid models are not working apps, so we cannot pass them into
796-                # the test runner with the other test_labels
797-                test_labels.remove(module_name)
798-            except ValueError:
799-                pass
800 
801     # If GeoDjango is used, add it's tests that aren't a part of
802     # an application (e.g., GEOS, GDAL, Distance objects).