| 30 | class Author(models.Model): |
| 31 | name = models.CharField(max_length=30) |
| 32 | |
| 33 | # Missing unique_together in the intermediate model: |
| 34 | |
| 35 | class Book(models.Model): |
| 36 | name = models.CharField(max_length=20) |
| 37 | authors = models.ManyToManyField(Author, through='AuthorsBooks') |
| 38 | |
| 39 | class AuthorsBooks(models.Model): |
| 40 | author = models.ForeignKey(Author) |
| 41 | book = models.ForeignKey(Book) |
| 42 | |
| 43 | # Extra data in the intermediate model: |
| 44 | |
| 45 | class Ballad(models.Model): |
| 46 | name = models.CharField(max_length=20) |
| 47 | authors = models.ManyToManyField(Author, through='AuthorsBallads') |
| 48 | |
| 49 | class AuthorsBallads(models.Model): |
| 50 | author = models.ForeignKey(Author) |
| 51 | ballad = models.ForeignKey(Ballad) |
| 52 | extra_data = models.IntegerField() |
| 53 | |
| 54 | class Meta: |
| 55 | unique_together = ('author', 'ballad') |
| 56 | |
| 57 | # Intermediate model PK field isn't an independent one: |
| 58 | |
| 59 | class Act(models.Model): |
| 60 | name = models.CharField(max_length=20) |
| 61 | authors = models.ManyToManyField(Author, through='AuthorsActs') |
| 62 | |
| 63 | class AuthorsActs(models.Model): |
| 64 | author = models.ForeignKey(Author, primary_key=True) |
| 65 | act = models.ForeignKey(Act) |
| 66 | |
| 67 | # This through-using m2m complies with all the requirements needed to be |
| 68 | # listed in ModelAdmin.fields, should validate succesfully: |
| 69 | |
| 70 | class Paper(models.Model): |
| 71 | name = models.CharField(max_length=20) |
| 72 | authors = models.ManyToManyField(Author, through='AuthorsPapers') |
| 73 | |
| 74 | |
| 75 | class AuthorsPapers(models.Model): |
| 76 | author = models.ForeignKey(Author) |
| 77 | paper = models.ForeignKey(Paper) |
| 78 | |
| 79 | class Meta: |
| 80 | unique_together = ('author', 'paper') |
| 81 | |
| 82 | # Intermediate model has a manually set PK, should work too: |
| 83 | |
| 84 | class Post(models.Model): |
| 85 | name = models.CharField(max_length=20) |
| 86 | authors = models.ManyToManyField(Author, through='AuthorsPosts') |
| 87 | |
| 88 | |
| 89 | class AuthorsPosts(models.Model): |
| 90 | mypk = models.AutoField(primary_key=True) |
| 91 | author = models.ForeignKey(Author) |
| 92 | post = models.ForeignKey(Post) |
| 93 | |
| 94 | class Meta: |
| 95 | unique_together = ('author', 'post') |
| 96 | |
| 97 | # Recursive m2m with through, should work too: |
| 98 | |
| 99 | class Writer(models.Model): |
| 100 | name = models.CharField(max_length=30) |
| 101 | similar = models.ManyToManyField('self', through='Influence', symmetrical=False) |
| 102 | |
| 103 | |
| 104 | class Influence(models.Model): |
| 105 | inspirator = models.ForeignKey(Writer, related_name='influenced_by') |
| 106 | inspired = models.ForeignKey(Writer, related_name='influenced') |
| 176 | # Regression test for #12203 - Fail more gracefully when a M2M field that |
| 177 | # specifies the 'through' option is included in the 'fields' ModelAdmin option. |
| 178 | |
| 179 | >>> class BookAdmin(admin.ModelAdmin): |
| 180 | ... fields = ['authors'] |
| 181 | |
| 182 | >>> validate(BookAdmin, Book) |
| 183 | Traceback (most recent call last): |
| 184 | ... |
| 185 | ImproperlyConfigured: BookAdmin.fields: Included 'authors' ManyToManyField field uses 'through' option but specifies a non suitable intermediate model (AuthorsBooks). |
| 186 | |
| 187 | >>> class BalladAdmin(admin.ModelAdmin): |
| 188 | ... fields = ['authors'] |
| 189 | |
| 190 | >>> validate(BalladAdmin, Ballad) |
| 191 | Traceback (most recent call last): |
| 192 | ... |
| 193 | ImproperlyConfigured: BalladAdmin.fields: Included 'authors' ManyToManyField field uses 'through' option but specifies a non suitable intermediate model (AuthorsBallads). |
| 194 | |
| 195 | >>> class ActAdmin(admin.ModelAdmin): |
| 196 | ... fields = ['authors'] |
| 197 | |
| 198 | >>> validate(ActAdmin, Act) |
| 199 | Traceback (most recent call last): |
| 200 | ... |
| 201 | ImproperlyConfigured: ActAdmin.fields: Included 'authors' ManyToManyField field uses 'through' option but specifies a non suitable intermediate model (AuthorsActs). |
| 202 | |
| 203 | >>> class PaperAdmin(admin.ModelAdmin): |
| 204 | ... fields = ['authors'] |
| 205 | |
| 206 | >>> validate(PaperAdmin, Paper) |
| 207 | |
| 208 | >>> class PostAdmin(admin.ModelAdmin): |
| 209 | ... fields = ['authors'] |
| 210 | |
| 211 | >>> validate(PostAdmin, Post) |
| 212 | |