在Django中查找多对多类别树的根

在Django中查找多对多类别树的根,django,many-to-many,Django,Many To Many,我有一个Django模型,比如: class Category(models.Model): status=models.CharField(max_length=16) machineName=models.CharField(max_length=50) readableName=models.CharField(max_length=100) description=models.CharField(max_length=1024) parents=

我有一个Django模型,比如:

class Category(models.Model):
    status=models.CharField(max_length=16)
    machineName=models.CharField(max_length=50)
    readableName=models.CharField(max_length=100)
    description=models.CharField(max_length=1024)
    parents=models.ManyToManyField('self')
每个类别可能存在于许多家长中。有些类别没有父类别,它们是“根”类别。在纯SQL中,我可以通过以下方式找到它们:

SELECT "readableName"
FROM foo_category AS c
LEFT JOIN foo_category_parents AS cp ON (c.id=cp.from_category_id)
WHERE cp.to_category_id IS NULL;
事实上,这很有效。如何通过Django-y调用找到“无父类别列表”?我试过:

# Says "Cannot resolve keyword 'is_null' into field."
Category.objects.filter(parents__is_null=True)
# Says "Join on field 'id' not permitted."
Category.objects.filter(parents__pk_null=True)

但如前所述,两者都不起作用。

Django的多对多场通常是对称运行的(见下图)。当您对自己执行manytomy时,这意味着将创建一个反向manytomy条目,因此事实上,每个具有父级的类别都将是父级的父级(如果有意义的话)

换言之:

a = Category.objects.create(name='a')
b = Category.objects.create(name='b')
b.parents.add(a)

print b.parents.all() # produces [a]
print a.parents.all() # produces [b], which is why your filter is failing
为了解决这个问题,有一个特殊的选择:

class Category(models.Model):
    # ... as above ...
    parents=models.ManyToManyField('self', symmetrical=False)
现在,您可以使用以下工具获取父类别:

 Category.objects.filter(parents=None)
非常感谢,“对称=错误”和“父母=无”正是我需要的。当然,“parents=None”的语法比我失败的尝试要好得多!