2012-01-17 2 views
3

J'essaye de concevoir ma première base de données et je me suis un peu coincé. Le design est le suivant: Vous avez un auteur qui peut avoir beaucoup de livres. Chaque livre peut avoir plusieurs pages. Chaque page peut avoir beaucoup d'images. Chaque page est unique (ForeignKey). Les images peuvent ne pas être uniques (vous pouvez utiliser la même image dans différentes pages/livres, donc cela devrait être ManyToMany). Mon problème est que je ne peux pas obtenir les images à ManyToManyField en utilisant Inlines.Django Design de base de données: ManyToManyField lors de l'utilisation d'Inlines

Si je change ForeignKey à ManyToMany, j'obtiens l'exception "<class 'books.models.Picture'> has no ForeignKey to <class 'books.models.Page'>". J'ai regardé here et here, mais je n'ai aucune idée de comment l'appliquer dans mon cas.

Voici comment mon models.py ressemble à:

class Author(models.Model): 
    name = models.CharField(max_length=30) 
    email = models.EmailField() 

class Book(models.Model): 
    author = models.ForeignKey(Author) 
    title = models.CharField(max_length=50) 

class Page(models.Model): 
    book = models.ForeignKey(Book) 
    contents = models.TextField(max_length=15999) 

class Picture(models.Model): 
    page = models.ForeignKey(Page) # ideally, this should be many-to-many 
    picture_uuid = models.CharField(max_length=36) 

Dans mon interface d'administration, je voudrais avoir tous les livres auteur a écrit sur la page de l'auteur. Aussi, j'aimerais avoir toutes les pages d'un livre dans la page des livres et ainsi de suite. Mon admin.py ressemble donc à ceci:

class PictureAdmin(admin.ModelAdmin): 
    list_display = ('id', 'picture_uuid') 

class PictureInline(admin.TabularInline): 
    model = Picture 

class PageAdmin(admin.ModelAdmin): 
    list_display = ('id', 'page_uuid') 

    inlines = [ 
     PictureInline, 
     ] 

class PageInline(admin.TabularInline): 
    model = Page 

class BookAdmin(admin.ModelAdmin): 
    list_display = ('id', 'title') 

    inlines = [ 
     PageInline, 
     ] 

class BookInline(admin.TabularInline): 
    model = Book 

class AuthorAdmin(admin.ModelAdmin): 
    list_display = ('id', 'name', 'email') 

    inlines = [ 
     BookInline, 
     ] 

Répondre

3

Vous ne pouvez pas utiliser ManyToManyFields directement inline. Les Inlines doivent avoir une clé étrangère dans le modèle en cours d'édition, et bien sûr, l'enfant réel ne le fait pas. Si vous souhaitez modifier une ligne M2M, le mieux que vous pouvez faire est d'utiliser la table through, de sorte que vous auriez besoin de modifier votre InlineModelAdmin comme ceci:

class PictureInline(admin.TabularInline): 
    model = Page.pictures.through 

qui exige que le ManyToManyField être sur le modèle Page:

class Page(models.Model): 
    ... 
    pictures = models.ManyToManyField(Picture) 
+0

Works, sauf que j'ai maintenant deux sections sur une page où je peux sélectionner des photos. Un menu déroulant de clé étrangère pour sélectionner une image et un menu normal plusieurs-à-plusieurs pour sélectionner une image. Comment puis-je me débarrasser de la seconde? –

+1

Il suffit d'ajouter le champ réel à votre 'ModelAdmin'' exclude' –

+0

Merci, vient de le faire et il a disparu. Problème suivant, cependant: si j'essaie de mettre à nouveau la même image sur une page, j'obtiendrai l'erreur (dans l'interface Django Admin): "La relation page-image avec cette page et cette image existe déjà." Pourquoi cela est-il ainsi? Je pensais que c'est maintenant une relation plusieurs-à-plusieurs, ie je devrais être capable d'avoir la même image sur une page deux fois ou trois fois ou quatre fois etc –

0

Selon la documentation https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-models vous devez définir un attribut model dans votre ligne très bien

+2

Umm ... Il l'a fait. Et, ce n'est pas le problème de toute façon. –

+0

@ChrisPratt si vous voyez le lien que j'ai pointé, vous remarquerez que ma réponse est à peu près la même que la vôtre, quand j'ai dit définir un modèle que je voulais dire model = Page.pictures.through – armonge

+2

Alors pourquoi publier une réponse qui suggère simplement la même chose que ma réponse? –