web-dev-qa-db-ja.com

Django ManyToManyFieldの順序付け

これが私のモデルのセットアップ方法の抜粋です。

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
23
Brian

私はちょうどこれを通り抜けました。

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年に使用できるかどうかはわかりませんが、現在は確かにそうです。

21
zalun

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

順序付けられたクエリセットが提供されますが、この場合、クエリセットに含まれるのはアカウントオブジェクトではなくprofileaccountオブジェクトです...したがって、それぞれに移動するには、別のDjangoレベルの関係を使用する必要があります関連するアカウント:

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

関連する名前をProfileAccountsに追加してから、その 'related_name__number'を持つアカウントの順序を変更します。 related_nameとnumberの間に2つのアンダースコアがあることに注意してください。下記参照:

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',)
2
shabss

それは私のために働いた:

Profile.objects.account.order_by('profileaccounts')
2
Murat Çorlu

プロファイルにタイプミスがありますが(「アカウント」を意味すると思う場合は「アカウント」です)、さらに重要なのは、モデル内で単数形/複数形が混在していることです。

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'):が機能するはずです。他の問題がないと仮定します。

1

私はこれを多くのモデルで使用していますが、私の意見では(他のすべての回答とは異なり)、_order_by_を再度指定する必要はありません。これは、throughモデルですでに指定されているためです。もう一度指定すると、DRY(繰り返さないでください)の原則に違反します。

私は使うだろう:

_qs = profile.profileaccounts_set.all()
_

これにより、構成された順序を使用して、プロファイルに関連付けられたProfileAccountsのセットが提供されます。次に:

_for pa in qs:
    print(pa.account.name)
_

ボーナスポイントについては、クエリで_select_related_を使用して、プロセス全体を高速化することもできます。

0
racitup

この特定の問題の最も簡単な解決策は

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