Django ManyToManyField使用直通订购

时间:2010-10-08 20:07:37

标签: python django many-to-many

以下是我的模型设置的摘要:

class Profile(models.Model):     
    name = models.CharField(max_length=32)

    accout = models.ManyToManyField(
        'project.Account',
        through='project.ProfileAccount'
    )

    def __unicode__(self)
        return self.name

class Accounts(models.Model):
    name = models.CharField(max_length=32)
    type = models.CharField(max_length=32)

    class Meta:
        ordering = ('name',)

    def __unicode__(self)
        return self.name

class ProfileAccounts(models.Model):
    profile = models.ForeignKey('project.Profile')
    account = models.ForeignKey('project.Accounts')

    number = models.PositiveIntegerField()

    class Meta:
        ordering = ('number',)

然后,当我访问帐户时,如何在中间ProfileAccounts模型中按“数字”排序,而不是在帐户模型中使用默认的“名称”?:

for acct_number in self.profile.accounts.all():
    pass

这不起作用,但是我希望它如何访问这些数据的要点是:

for scanline_field in self.scanline_profile.fields.all().order_by('number'):
    pass

7 个答案:

答案 0 :(得分:21)

我刚刚经历过这个。

class Profile(models.Model):     
    accounts = models.ManyToManyField('project.Account',
                                      through='project.ProfileAccount')

    def get_accounts(self):
        return self.accounts.order_by('link_to_profile')


class Account(models.Model):
    name = models.CharField(max_length=32)


class ProfileAccount(models.Model):
    profile = models.ForeignKey('project.Profile')
    account = models.ForeignKey('project.Account', related_name='link_to_profile')
    number = models.PositiveIntegerField()

    class Meta:
        ordering = ('number',)

除了Article.name之外,我删除了偏离主题的字段。 这是我发现的最短的解决方案,不知道是否可以在2010年使用,但现在肯定是。

答案 1 :(得分:5)

ManyToManyField管理器允许您直接从相关模型中选择/过滤数据,而无需在django级别上使用直通模型的任何模型连接...

同样地,

如果您尝试:

pr = Profile.objects.get(pk=1)
pr.account.all()

返回与该个人资料相关的所有帐户。如您所见,与直通模型ProfileAccount没有直接关系,因此此时您无法使用M2M关系...您必须使用与贯穿模型的反向关系并过滤结果...

pr = Profile.objects.get(pk=1)
pr.profileaccount_set.order_by('number')

会给你一个有序的查询集,但是,在这种情况下,你在queryset中拥有的是profileaccount对象,而不是帐户对象......所以你必须使用另一个django级别关系来转到每个相关的帐户:

pr = Profile.objects.get(pk=1)
for pacc in pr.profileaccount_set.order_by('number'):
    pacc.account

答案 2 :(得分:2)

这对我有用:

Profile.objects.account.order_by('profileaccounts')

答案 3 :(得分:1)

配置文件中有一个拼写错误(当我认为你的意思是“帐户”时,它是“accout”),但更重要的是你在模型中混合了你的单数/复数形式。

在Django中,练习通常是将您的类命名为单数,而您的ManyToManyField名称为复数。所以:

class Profile(models.Model):     
    name = models.CharField(max_length=32)

    accounts = models.ManyToManyField(
        'Account',
        through='ProfileAccount'
    )

    def __unicode__(self)
        return self.name

class Account(models.Model):
    name = models.CharField(max_length=32)
    type = models.CharField(max_length=32)

    class Meta:
        ordering = ('name',)

    def __unicode__(self)
        return self.name

class ProfileAccount(models.Model):
    profile = models.ForeignKey(Profile)
    account = models.ForeignKey(Account)

    number = models.PositiveIntegerField()

    class Meta:
        ordering = ('number',)

我对您尝试使用此模型所做的事情感到有些困惑,但如果您进行了这些更改,则for acct_number in self.profile.accounts.all().order_by('number'):应该可以正常工作。假设没有其他问题。

答案 4 :(得分:1)

将相关名称添加到ProfileAccounts,然后使用“related_name__number”更改Accounts中的顺序。请注意related_name和number之间的两个下划线。见下文:

class Accounts(models.Model):
    .
    .
    .
    class Meta:
        ordering = ('profile_accounts__number',)


class ProfileAccounts(models.Model):
    .
    .
    .
    account = models.ForeignKey('project.Accounts', related_name='profile_accounts')

    number = models.PositiveIntegerField()

    class Meta:
        ordering = ('number',)

答案 5 :(得分:0)

这个特定问题的最简单解决方案似乎是

for acct in self.profile.accounts.order_by('profileaccounts'):
    pass

答案 6 :(得分:0)

我在很多模型上都有这个,但在我看来(并且与其他所有答案不同)你不应该再次指定order_by,因为,它是it,已在through模型中指定。再次指定它会打破DRY(不要重复自己)原则。

我会用:

qs = profile.profileaccounts_set.all()

这将使用您配置的排序提供与配置文件关联的ProfileAccounts集。然后:

for pa in qs:
    print(pa.account.name)

对于奖励积分,您还可以在查询中使用select_related来加快整个过程。