Django ManyToManyField ordering using through

后端 未结 7 2329
傲寒
傲寒 2020-12-13 20:27

Here is a snippet of how my models are setup:

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

    accout = models.ManyToManyFie         


        
相关标签:
7条回答
  • 2020-12-13 20:38

    a ManyToManyField manager allows you to select/filter data from the related model directly, without using any model connection of the through model on your django level...

    Likewise,

    if you try:

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

    returns you all account related to that profile. As you see, there exists no direct relation to the through model ProfileAccount, so you can not use the M2M relation at this point... You must use a reverse relation to the through model and filter the results...

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

    will give you an ordered queryset, but, in this case, what you have in queryset is profileaccount objects, not account objects... So you have to use another django level relation to go to each related account with:

    pr = Profile.objects.get(pk=1)
    for pacc in pr.profileaccount_set.order_by('number'):
        pacc.account
    
    0 讨论(0)
  • 2020-12-13 20:41

    I just came through this.

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

    I removed the fields which were off-topic except of Account.name. That's the shortest solution I've found, no idea if it was possible to use in 2010, but it certainly is now.

    0 讨论(0)
  • 2020-12-13 20:42

    There's a typo in the Profile (it's "accout" when I think you mean "account"), but more importantly you have your singular/plural forms mixed up in the model.

    In Django the practice is generally to name your classes singular, and your ManyToManyField names plural. So:

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

    I'm a little confused at what you're trying to do with this model, but if you make those changes, then for acct_number in self.profile.accounts.all().order_by('number'): should work. Assuming no other issues.

    0 讨论(0)
  • 2020-12-13 20:43

    Add the related name to ProfileAccounts and then change the ordering in Accounts with that 'related_name__number'. Note two underscores between related_name and number. See below:

    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',)
    
    0 讨论(0)
  • 2020-12-13 20:43

    The easiest solution for this particular problem seems to be

    for acct in self.profile.accounts.order_by('profileaccounts'):
        pass
    
    0 讨论(0)
  • 2020-12-13 20:58

    That worked for me:

    Profile.objects.account.order_by('profileaccounts')
    
    0 讨论(0)
提交回复
热议问题