django - QuerySet 递归排序方法

1 投票
5 回答
2098 浏览
提问于 2025-04-15 13:03

我可能遇到了一个经典的问题,但我找不到任何代码片段能帮我解决。

我想按照全名对这个模型进行排序。

class ProductType(models.Model):
    parent   = models.ForeignKey('self', related_name='child_set')
    name     = models.CharField(max_length=128)

    def get_fullname(self):
        if self.parent is None:
            return self.name
        return u'%s - %s' % (unicode(self.parent), self.name)
    fullname = property(get_fullname)
  1. 我尝试按“parent”排序,但出现了无限循环错误。使用“parent__id”排序也不太好。

  2. 我不太明白如何使用annotate()来连接字符串字段。

  3. 我添加了一个自定义管理器,使用了sorted(),但是它返回的是一个列表对象,这样就导致我的forms.ModelChoiceField无法正常工作。

这是排序的代码

def all(self):
    return sorted(super(ProductTypeManager, self), key=lambda o: o.fullname)

在这个Django的丛林里还有什么其他的呢?感谢你的帮助。

5 个回答

0

这可能有效:

ProductType.objects.alL().order_by('parent__name', 'name')
1

或者,如果你想做的是生成一个树形结构,可以看看 django-mptt。这个工具还可以让你手动设置顺序。

2

我可能会创建一个去规范化的字段,然后根据这个字段进行排序。根据你的喜好,你可能想要重写一下 .save() 方法,或者使用信号来填充这个去规范化的字段。

class ProductType(models.Model):
    parent   = models.ForeignKey('self', related_name='child_set')
    name     = models.CharField(max_length=128)
    full_name     = models.CharField(max_length=128*4)

    def save(self, *args, **kwargs):
        if not full_name:
            self.full_name = self.get_fullname()
        super(ProductType, self).save(*args, **kwargs)


    def get_fullname(self):
        if self.parent is None:
            return self.name
        return u'%s - %s' % (unicode(self.parent), self.name)

然后就可以正常地根据 full_name 进行排序了。

撰写回答