2009-09-16 3 views
6

Jestem nowy w Django i mam kilka problemów z myśleniem o wielu związkach i Manytoone (tj. Kluczu obcym).Django Relationships

Moja konfiguracja jest właśnie taka.

mam klasy A, klasy B, klasy C przedmiot

Każda klasa B muszą należeć do klasy A przedmiot. Nie mogą należeć do więcej niż jednego obiektu klasy A. Bardziej praktycznym przykładem może być, jeśli klasa A to zespół muzyczny, a klasa B to utwór z tym zespołem. Większość zespołów będzie mieć więcej niż jedną piosenkę, ale każda piosenka musi należeć do zespołu (w tym przykładzie utwór nigdy nie może mieć wielu pasm).

Klasa C to lista poszczególnych członków zespołu. Tak więc każdy członek zespołu może być powiązany z dowolną liczbą utworów, a także z dowolną liczbą pasm. Innymi słowy członkiem paśmie X może być również członkiem Band Y.

Moje pytanie wtedy byłoby

jaki sposób mogę korzystać z relacji ForeignKey i ManytoMany w tym kontekście?

Ten przykład ma na celu ułatwienie zrozumienia mojej sytuacji i wyjaśnienie mojego problemu. Chciałbym, aby administrator wyświetlał dla każdego obiektu klasy C obiekty klasy B lub klasy A, do których należy klasa C. To samo dotyczy klasy B i klasy A.

Jeśli spojrzysz na obiekty klasy A, powinieneś być w stanie wyświetlić listę wszystkich obiektów klasy B, które należą do tego konkretnego obiektu klasy A.

Wszelkie doceniane wejście.

+1

Manytoone? Czy to gdzieś w Szkocji? – ijw

Odpowiedz

3

To wszystko jest dość proste. Użyłem opisowych nazw poniżej, aby ułatwić ich przestrzeganie.

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 - Świetna odpowiedź - warto się zastanowić, dlaczego masz 'ManyToManyField ('Band')', ale 'ForeignKey (Band)', ponieważ obecnie wygląda na to, że musisz zdefiniować 'ManyToManyField' i' ForeignKey', a nie w kolejności, w której klasy zostały zdefiniowane. –

+0

Dobra uwaga, faktycznie zmieniłem klasy, więc nie ma potrzeby używania formularza. –

+0

Witam Dziękuję za odpowiedź. Rozumiem twoją odpowiedź, ale w tej chwili problemem jest strona administratora. Jeśli wchodzę do nowego zespołu BandMember, pojawia się monit o określenie, z którymi utworami jest on związany. A jeśli otworzę członka zespołu, mogę zobaczyć listę upuszczeń, która wydaje się zawierać id każdej piosenki. Jeśli wpiszesz bandmember (który ma określony numer ID - który można znaleźć również w tabeli utworów) po utworzeniu go, gdy spojrzysz na zespół memeber, administrator powinien to wyświetlić. Czy muszę zrobić specjalne widoki dla administratora, aby to zrobić? – Consiglieri

11

Oto jak bym go skonfigurować (w Twojej 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 

skonfigurować tak:

  • member.band_set.all() daje wszystkie pasma członek należący do
  • band.members.all() udostępnia członkom zespołu
  • song.band daje pasmo dla tej piosence
  • band.song_set.all() daje wszystkie utwory dla zespołu

Należy pamiętać, że band_set na członka i song_set na paśmie są „reverse” relacji. Nie są one wyraźnie zdefiniowane w modelach, ale Django ustawia je dla Ciebie w sposób przejrzysty. Można je dostosować, używając parametru related_name w definicji pola.Przykład:

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

pozwoli Ci uzyskać wszystkie pasm dla członka następująco:

member.bands.all() 

Administrator automatycznie dostarczyć następujące:

  • Pokaż wszystkich członków do zespołu w lista wielokrotnego wyboru
  • Pokaż zespół dla utworu na jednej liście wyboru

Jeśli jednak chcesz zobaczyć utwory zespołu, musisz dokonać niewielkiej personalizacji.

W swojej 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) 

To pozwoli Ci zobaczyć utwory z prawej strony administratora - i edytować lub dodawać je dobrze! Podążając za tym szablonem, możesz również pokazać wszystkie zespoły dla członka.

można uzyskać bardziej szczegółowe wprowadzenie do personalizacji administracyjnej na http://docs.djangoproject.com/en/dev/intro/tutorial02/

+0

+1 za uwzględnienie admin.py – Alasdair

+0

Dzięki, odpowiedzi nadchodzą tak szybko, że nie byłem w stanie nadrobić zaległości :). Dam mu wir i zobaczę, czy uda mi się go zastosować do twoich sugestii. – Consiglieri

+0

Cześć, wygląda na to, że działa - mimo że w Pasie onlky wyświetla "obiekt memmber", a nie nazwę członka. Wiem, że mogę zrobić listing_danych, ale nie wiem, jak ustawić listing_dokumentu w memebr innej klasy. tj. w klasie BandAdmin przy użyciu list_display = ("Member.firstname", "Memeber.lastname") nie działa, a jeśli ustawię klasę MemberAdmin z wyżej wymienionym display_list, otrzymam listę wyświetlaną w Memeber viw, ale lista w Widok pasma wciąż wyświetla tylko "element członkowski", ale nie nazwę członka. Jestem pewien, że to jest trywialne, ale doceniłbym pomocną dłoń w tym – Consiglieri