Django ManyToManyField ordering using through?

Oto fragment konfiguracji moich modeli:]}

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

Następnie, gdy uzyskuję dostęp do kont, jak Mogę sortować według "numeru" w modelu profilu Pośrednika, a nie domyślnej "nazwy" w modelu kont?:

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

To nie działa, ale jest sednem tego, jak chcę, aby uzyskać dostęp do tych danych:

for scanline_field in self.scanline_profile.fields.all().order_by('number'):
    pass
Author: Tshepang, 2010-10-09

7 answers

Właśnie przez to przechodziłam.

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

Usunąłem pola, które były poza tematem z wyjątkiem Article.name. To najkrótsze rozwiązanie, jakie znalazłem, Nie wiem, czy było możliwe do wykorzystania w 2010 roku, ale na pewno jest teraz.

 20
Author: zalun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-02 07:55:53

Menedżer ManyToManyField pozwala wybrać / filtrować dane bezpośrednio z powiązanego modelu, bez użycia jakiegokolwiek połączenia modelu przelotowego na poziomie django...

Podobnie,

Jeśli spróbujesz:

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

Zwraca Ci wszystkie konta powiązane z tym profilem. Jak widzisz, nie istnieje bezpośrednia relacja do profilu modelu przelotowego, więc nie możesz w tym momencie użyć relacji M2M... Musisz użyć odwrotnej relacji do modelu przelotowego i filtrować wyniki...

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

Da ci uporządkowany queryset, ale w tym przypadku to, co masz w queryset, to obiekty profileaccount, a nie Obiekty konta... Więc musisz użyć innej relacji poziomu django, aby przejść do każdego powiązanego konta z:

pr = Profile.objects.get(pk=1)
for pacc in pr.profileaccount_set.order_by('number'):
    pacc.account
 4
Author: FallenAngel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-13 12:56:54

Jest literówka w profilu (to "accout", kiedy myślę, że masz na myśli "konto"), ale co ważniejsze, masz swoje formy liczby pojedynczej/mnogiej pomieszane w modelu.

W Django praktyka polega na nazywaniu Twoich klas w liczbie pojedynczej, a twojego ManyToManyField w liczbie mnogiej. Więc:

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',)
Jestem trochę zdezorientowany, co próbujesz zrobić z tym modelem, ale jeśli wprowadzisz te zmiany, to powinno zadziałać. Zakładając, że nie ma innych problemów.
 1
Author: Andrew Gorcester,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-10 22:19:38

Dodaj powiązaną nazwę do ProfileAccounts, a następnie zmień kolejność na kontach za pomocą 'powiązana_nazwa_ _ numer'. Zwróć uwagę na dwa podkreślenia między related_name i number. Patrz poniżej:

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
Author: shabss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-09 03:36:11

To mi pomogło:

Profile.objects.account.order_by('profileaccounts')
 1
Author: Murat Çorlu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-02 09:07:49

Najprostszym rozwiązaniem tego konkretnego problemu wydaje się być

for acct in self.profile.accounts.order_by('profileaccounts'):
    pass
 0
Author: Mikus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-30 14:58:42

Mam to na kilku moich modelach, ale moim zdaniem (i w przeciwieństwie do wszystkich innych odpowiedzi) nie powinieneś ponownie podawać order_by, ponieważ, cóż, jest to już określone w modelu through. Podanie go ponownie łamie zasadę DRY (don ' t repeat yourself).

Użyłbym:

qs = profile.profileaccounts_set.all()

To daje zestaw kont ProfileAccounts powiązanych z profilem przy użyciu skonfigurowanego zamówienia. Wtedy:

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

W przypadku punktów bonusowych można również przyspieszyć cały proces poprzez użycie select_related w zapytaniu.

 0
Author: racitup,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-04 00:52:18