2 Stimmen

Suche nach den Wurzeln eines Many-to-Many-Kategorienbaums in Django

Ich habe ein Django-Modell wie:

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

Jede Kategorie kann in vielen Elternteilen vorkommen. Einige Kategorien haben keine Eltern, sie sind die "Root"-Kategorien. In einfachem SQL könnte ich sie finden durch:

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;

Und in der Tat, das funktioniert gut. Wie finde ich die "Liste der Kategorien ohne Eltern" mit einem Django-y Aufruf? Ich habe es versucht:

# 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)

Aber wie gesagt, beides funktioniert nicht.

7voto

Jarret Hardie Punkte 89900

Djangos Many-to-many-Felder arbeiten normalerweise symmetrisch (siehe diese Eintrag in den Django-Dokumenten ). Wenn Sie einen ManyToMany-Eintrag auf sich selbst anwenden, bedeutet dies, dass ein umgekehrter ManyToMany-Eintrag erstellt wird, d. h. jede Kategorie mit einer übergeordneten Kategorie ist die übergeordnete Kategorie der übergeordneten Kategorie (falls dies sinnvoll ist).

Mit anderen Worten:

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

Um dies zu umgehen, gibt es eine spezielle Option:

class Category(models.Model):
    # ... as above ...
    parents=models.ManyToManyField('self', symmetrical=False)

Jetzt können Sie die übergeordneten Kategorien mit abrufen:

 Category.objects.filter(parents=None)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X