Найти корни дерева категорий многие ко многим в Джанго - PullRequest
2 голосов
/ 20 мая 2009

У меня есть модель 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)

Но, как уже было отмечено, ни одна из них не работает.

1 Ответ

7 голосов
/ 20 мая 2009

Поля «многие ко многим» в Django обычно работают симметрично (см. Эту запись в документации Django ). Когда вы делаете ManyToMany для себя, это означает, что будет создана обратная запись ManyToMany, поэтому фактически каждая категория с родителем будет родительской для родителя (если это имеет смысл).

Другими словами:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...