2009-09-16 14 views
6

Sono nuovo a Django e ho qualche problema a farmi un'idea di molte relazioni e Manytoone (la chiave straniera).Relazioni Django

Il mio setup è questo.

devo classe A, Classe B, Classe C oggetto

Ogni classe B deve appartenere a una classe di un oggetto. Non possono appartenere a più di un oggetto di Classe A. Un esempio più pratico potrebbe essere se la Classe A è una Music Band e la classe B è una canzone con quella Band. La maggior parte delle band avrà più di una canzone, ma ogni canzone deve appartenere a una band (in questo esempio una canzone non può mai avere più bande).

Classe C è un elenco di singoli membri della Banda. Quindi ogni membro della band può essere associato ad un numero arbitrario di canzoni e ad un numero arbitrario di Bands. In altre parole, un membro della banda X può anche essere un membro della banda Y.

La mia domanda allora sarebbe

come faccio a utilizzare i rapporti ForeignKey e ManyToMany in questo contesto?

Questo esempio è concepito solo per semplificare la comprensione della situazione e per aiutarmi a spiegare il problema. Vorrei che l'amministratore visualizzasse per ogni oggetto di classe C quali oggetti di classe B o di classe A che appartengono alla classe C. Lo stesso vale per la Classe B e la Classe A.

Se si guardano gli oggetti di Classe A dovresti essere in grado di vedere un elenco di tutti gli oggetti di Classe B che appartengono a quel particolare oggetto di Classe A.

Qualsiasi e tutti gli input apprezzati.

+1

ManyToOne? È da qualche parte in Scozia? – ijw

risposta

3

Questo è tutto abbastanza semplice. Ho usato i nomi descrittivi sotto, per renderlo più facile da seguire.

class Band(models.Model): 
    name = models.CharField(max_length=255) 

class BandMember(models.Model): 
    name = models.CharField(max_length=255) 
    bands = models.ManyToManyField(Band) 

class Song(models.Model): 
    name = models.CharField(max_length=255) 
    band = models.ForeignKey(Band) 

# get a band 
myband = Band.objects.get(name='myband') 

# all songs from that band 
print myband.song_set.all() 

# all members of that band 
print myband.bandmembers.all() 


# get a specific band member 
dave = BandMember.objects.get(name='Dave') 

# what bands is Dave a member of? 
print dave.bands.all() 

# what songs has Dave sung? (slightly more complicated) 
print Song.objects.get(band__bandmember=dave) 
+0

+1 - Ottima risposta - potrebbe valere la pena di essere modificato perché hai 'ManyToManyField ('Band')' ma 'ForeignKey (Band)', perché al momento sembra che sia il modo in cui devi definire 'ManyToManyField' e' ForeignKey' rispettivamente, piuttosto che fare con l'ordine in cui sono state definite le classi. –

+0

Buon punto, ho effettivamente riordinato le classi quindi non c'è bisogno di usare il form per le stringhe. –

+0

Ciao Grazie per la risposta. Capisco la tua risposta, ma il problema al momento è la pagina di amministrazione. Se inserisco un nuovo BandMember, mi viene richiesto di dire a quali canzoni è connesso. E se apro un membro della band posso vedere una lista che sembra contenere l'id di ogni canzone. Se inserisco un membro della band (che ha un ID particolare - che può anche essere trovato nella tabella delle song) una volta che è stato creato quando si guarda il memeber della banda, l'admin dovrebbe mostrarlo. Devo creare visualizzazioni speciali per l'amministratore per fare questo? – Consiglieri

11

Ecco come mi piacerebbe impostare il tutto (nel vostro models.py)

class Member(models.Model): 
    name = models.CharField(max_length=100) 
    ... 

    def __unicode__(self): 
     return self.name 


class Band(models.Model): 
    name = models.CharField(max_length=100) 
    members = models.ManyToManyField(Member) 
    ... 

    def __unicode__(self): 
     return self.name 


class Song(models.Model): 
    name = models.CharField(max_length=100) 
    band = models.ForeignKey(Band) 
    ... 

    def __unicode__(self): 
     return self.name 

Impostare in questo modo:

  • member.band_set.all() ti dà tutte le bande di un membro appartiene
  • band.members.all() ti dà i membri di una band
  • song.band ti dà la band per quella canzone
  • band.song_set.all() ti dà tutte le canzoni di una band

Si noti che il band_set sul membro e la song_set sulla banda sono "Reverse" relazioni. Non sono definiti esplicitamente nei modelli, ma Django li imposta in modo trasparente. È possibile personalizzarli utilizzando il parametro related_name nella definizione del campo.Esempio:

class Band(models.Model): 
    members = models.ManyToManyField(Member,related_name='bands') 

sarebbe permetterà di ottenere tutte le band per un membro come segue:

member.bands.all() 

L'amministratore fornirà automaticamente le seguenti:

  • Mostra tutti i membri di una band in un elenco a selezione multipla
  • Mostra la band per una canzone in un singolo elenco di selezione

Tuttavia, se si desidera vedere le canzoni di una band, è necessario eseguire una piccola personalizzazione dell'amministratore.

Nel vostro admin.py:

from django.contrib import admin 

class SongInline(admin.StackedInline): 
    model = Song 
    extra = 1 

class BandAdmin(admin.ModelAdmin): 
    inlines = [SongInline] 

admin.site.register(Band,BandAdmin) 
admin.site.register(Member) 
admin.site.register(Song) 

Questo vi permetterà di visualizzare i brani direttamente dalla pagina di amministrazione - e modificare o aggiungere loro pure! Seguendo questo modello è possibile mostrare tutte le bande per un membro.

È possibile ottenere una più dettagliata introduzione alla personalizzazione di amministrazione a http://docs.djangoproject.com/en/dev/intro/tutorial02/

+0

+1 per includere admin.py – Alasdair

+0

Grazie, le risposte stanno arrivando così velocemente che non sono riuscito a recuperare :). Devo dargli un vortice e vedere se riesco a farlo funzionare con i tuoi suggerimenti. – Consiglieri

+0

Ciao di nuovo, sembra funzionare, anche se in Band onlky mostra un "oggetto memmber" e non il nome del membro. So che posso fare un list_display ma non so come impostare list_display su memebr di un'altra classe. cioè nella classe BandAdmin usando list_display = ('Member.firstname', 'Memeber.lastname') non funziona, e se imposto una classe MemberAdmin con il list_display sopra menzionato ottiene una visualizzazione di lista nel Memeber viw, ma la lista in La vista della banda mostra ancora solo un "oggetto membro" ma non il nome del membro. Sono sicuro che questo è banale ma apprezzerei una mano su questo – Consiglieri