2012-03-28 18 views
1

Ich schreibe eine App, wo ich Daten mit Benutzerpaaren verknüpfen müssen. Zum Beispiel wird jedem Benutzerpaar ein Kompatibilitätsfaktor zugeordnet, ebenso wie Viele-zu-Viele-Beziehungen, wie zum Beispiel Künstler, die sie gemeinsam haben. Ich bin verwirrt über den besten Weg, dies zu tun, es scheint, als ob ich eine Kombination von 1) Benutzer über die Eins-zu-Eins-Beziehung, 2) mit einer rekursiven Beziehung zu Selbst auf der Benutzer-Tabelle, 3) gekoppelt wäre mit specifying extra fields on M2M relationships, aber ich kann meinen Kopf nicht darum herumwickeln, wie das Modell aussehen würde.Viele-zu-viele-Beziehung auf Benutzer Tabelle in Django

Dies ist, wie ich das bin derzeit erreichen, was ich davon ausgehen, nicht der beste Weg, es zu tun ist, wie es für jede Abfrage zwei Durchgänge durch die DB erfordert:

in models.py (psuedo-Code übernehmen gibt es eine Künstler-Klasse):

class UserProfile(models.Model): 
    user = models.OneToOneField(User) 
    zipcode = models.CharField(max_length=16) 

def create_user_profile(sender, instance, created, **kwargs): 
    if created: 
     profile, created = UserProfile.objects.get_or_create(user=instance) 

post_save.connect(create_user_profile, sender=User)   

class Score(models.Model): 
    user = models.ForeignKey(User, related_name='score_first_user') 
    second_user = models.ForeignKey(User, related_name='score_second_user') 
    dh_score = models.DecimalField(decimal_places=2, max_digits=5) 
    cre_date = models.DateTimeField(auto_now_add=True) 
    upd_date = models.DateTimeField(auto_now=True) 
    deleted = models.BooleanField() 

    class Meta: 
     unique_together = ('user', 'second_user') 

class UserArtist(models.Model): 
    user = models.ForeignKey(User, related_name='userartist_first_user') 
    second_user = models.ForeignKey(User, related_name='userartist_second_user') 
    artist = models.ForeignKey(Artist) 
    cre_date = models.DateTimeField(auto_now_add=True) 
    upd_date = models.DateTimeField(auto_now=True) 
    deleted = models.BooleanField() 

dann in views.py speichere ich Partituren und gemeinsame Künstler so etwas wie (Pseudo-Code):

s = Score(user=u, second_user=second_user score=dh_score) 
s.save() 

und abrufen von ihnen etwas mit wie:

u = User.objects.get(username="%s" % username) 
user_scores = Score.objects.filter(Q(user=u.id) | Q(second_user=u.id)).order_by('-dh_score')[:10] 

for user_score in user_scores: 
# non-relevant logic to determine who is user and who is partner 
... 

    partner_artists = UserArtist.objects.filter((Q(user=u.id) & Q(second_user=partner.id))\ 
              | (Q(user=partner.id) & Q(second_user=u.id)) 
) 

Was ist der beste Weg, dies zu erreichen?

+0

Jemand gab eine Antwort, die ich in Frage stellte, was ich am Ende mit Modifikationen verwendete. Du hast es gelöscht, bevor ich es implementieren und testen konnte, wenn du noch da draußen bist, füge es neu hinzu, damit ich es annehmen kann! – kasceled

Antwort

4

Hier ist, wie ich die Benutzer-zu-Benutzer-Daten-Paarung erreicht, sowie Herstellung eine M2M-Beziehung zu dem Zwischentisch:

models.py

from django.db import models 
from django.contrib.auth.models import User 
from django.db.models.signals import post_save 

class UserProfile(models.Model): 
    user = models.OneToOneField(User) 
    pair = models.ManyToManyField('self', through='PairData', symmetrical=False) 


    def __unicode__(self): 
     return "%s's profile" % self.user 

def create_user_profile(sender, instance, created, **kwargs): 
    if created: 
     profile, created = UserProfile.objects.get_or_create(user=instance) 

post_save.connect(create_user_profile, sender=User) 

class PairData(models.Model): 
    first_user = models.ForeignKey(UserProfile, related_name='first_user') 
    second_user = models.ForeignKey(UserProfile, related_name='second_user') 
    raw_score = models.DecimalField(decimal_places=4, max_digits=9) 
    dh_score = models.DecimalField(decimal_places=2, max_digits=5) 
    distance = models.PositiveIntegerField() 
    cre_date = models.DateTimeField(auto_now_add=True) 

    def __unicode__(self): 
     return u"%s %s %f %d" % (self.first_user, self.second_user, self.dh_score, self.distance) 

class Artist(models.Model): 
    pair = models.ManyToManyField(PairData) 
    artist_name = models.CharField(max_length=256) 

    def __unicode__(self): 
     return u"%s" % self.artist_name 

Hier ist ein Beispiel dafür, wie ich fragte die Paardaten (views.py):

def matches(request, username): 
    user_profile = User.objects.get(username=username).get_profile() 
    pd = PairData.objects.filter(Q(first_user=user_profile) | Q(second_user=user_profile)).order_by('-dh_score') 

und die mit jedem Paar zugeordnet Künstler:

def user_profile(request, username): 
    user_profile = User.objects.get(username=username).get_profile() 
    viewers_profile = request.user.get_profile() 

    pair = PairData.objects.filter((Q(first_user=user_profile) & Q(second_user=viewers_profile)) \ 
            | (Q(first_user=viewers_profile) & Q(second_user=user_profile))) 

    artists = Artist.objects.filter(pair=pair) 

Wenn es eine bessere Möglichkeit gibt, abzufragen, ohne Q zu verwenden, bitte teilen!