Django中的用户表上的多对多关系

Django中的用户表上的多对多关系

问题描述:

我正在写一个应用程序,我需要将数据与用户对关联起来。例如,每个用户对都会有一个与它们相关的兼容性分数,以及多对多的关系,例如他们有共同点的艺术家。我对这样做的最佳方式感到困惑,似乎我会使用1)通过一对一关系扩展User,2)在User表上使用递归关系self,3)耦合与specifying extra fields on M2M relationships,但我不能包裹我的头模型看起来像。Django中的用户表上的多对多关系

这是我当前如何实现这一点,我认为是没有做到这一点的最好办法,因为它需要通过DB对于每个查询两遍:

在models.py(伪代码

,假设有一个艺术家类):

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() 
在views.py

然后我保存使用类似(伪代码)成绩和普通的艺人:

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

和使用的东西他们检索像:

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

什么是最好的方式来实现这一目标?

+0

有人提供了一个我在质疑的答案,这是我最终使用的修改。你可以在实施和测试之前删除它,如果你还在那里,请重新添加,以便我可以接受! – kasceled 2012-04-02 10:09:25

这里是我所完成的用户到用户数据配对,以及制备向中间表中的M2M关系:

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 

下面是如何的示例我查询的一对数据(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') 

和艺术家

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) 

如果有更好的方式来查询而不使用Q,请分享!