Django ManyToManyField заказ с использованием через - PullRequest
22 голосов
/ 09 октября 2010

Ниже приведен фрагмент настройки моих моделей:

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 ]

21 голосов
/ 06 июня 2012

Я только что прошел через это.

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 году, но, безусловно, сейчас.

5 голосов
/ 11 февраля 2011

менеджер 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')

даст вам упорядоченный набор запросов, но в этом случае в этом наборе есть объекты профиля учетной записи, а не объекты учетной записи ... Поэтому вам нужно использовать другое отношение уровня django, чтобы перейти к каждой связанной учетной записи с:

pr = Profile.objects.get(pk=1)
for pacc in pr.profileaccount_set.order_by('number'):
    pacc.account
2 голосов
/ 02 декабря 2015

Это сработало для меня:

Profile.objects.account.order_by('profileaccounts')
2 голосов
/ 09 апреля 2011

Добавьте связанное имя в ProfileAccounts, а затем измените порядок в Аккаунтах с этим «related_name__number».Обратите внимание на два подчеркивания между 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',)
1 голос
/ 10 октября 2010

В Профиле есть опечатка (это «accout», когда я думаю, что вы имеете в виду «account»), но, что более важно, в модели смешаны формы единственного / множественного числа.

В 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'): должно сработать. Предполагая, что никаких других проблем нет.

0 голосов
/ 04 октября 2017

У меня есть это на некоторых моих моделях, но по моему мнению (и в отличие от всех других ответов) вам не нужно указывать order_by снова, потому что, ну, это уже указано в модели through , Повторное указание нарушает принцип СУХОЙ (не повторяйся).

Я бы использовал:

qs = profile.profileaccounts_set.all()

Это дает набор учетных записей ProfileAccounts, связанных с профилем с использованием настроенного вами заказа. Тогда:

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

Для бонусных баллов вы также можете ускорить общий процесс, используя select_related в запросе.

0 голосов
/ 30 августа 2017

Самым простым решением для этой конкретной проблемы является

for acct in self.profile.accounts.order_by('profileaccounts'):
    pass
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...