sfendell
sfendell

Reputation: 5595

Making a tree structure in django models?

I want to have a model with 2 fields, children and parent. How do I do this in django? I have something like this

from django.db import models
class FooModel(models.Model)
    parent = models.ForeignKey('self', blank=True, null=True)
    children = models.ManyToOneRel('self', blank=True, null=True)

    def __init__(self, *args, **kwargs):
        super(FooModel, self).__init__(*args, **kwargs)
        self.parent.children.add(self)

But I don't think i'm supposed to use the ManyToOneRel like this (especially because it's giving me a keyword error on 'blank'). Any advice?

Upvotes: 16

Views: 22695

Answers (3)

Daniel Roseman
Daniel Roseman

Reputation: 599450

ManyToOneRel is an internal implementation class, it's not for use in your models.

But why do you think you need it anyway? As the documentation explains in detail, when you define a ForeignKey, you automatically get a reverse relation. So in your case, if you define parent then you automatically get self.foomodel_set already: and you can make it even more explicit by using the related_name parameter:

parent = models.ForeignKey('self', blank=True, null=True, related_name='children')

Note that if you're planning on doing complicated things with trees, you probably want to be using the django-mptt library.

Upvotes: 33

simplylizz
simplylizz

Reputation: 1704

class FooModel(models.Model)
    parent = models.ForeignKey('self', blank=True, null=True, related_name='children')


FooModel.objects.get(pk=1).children.all()

If you wish to cache use whatever you want: caching of query somewhere, store all children in parent as a flat list of pks, but don't forget to handle new entities to update this list. ManyToOneRel is for internal needs of django moreover it isn't an instance of Field class.

Upvotes: 3

Facundo Casco
Facundo Casco

Reputation: 10585

I could not find the documentation for ManyToOneRel so I looked up the code for it:

def __init__(self, to, field_name, related_name=None, limit_choices_to=None,
        parent_link=False, on_delete=None):

As you can see, there is no blank argument.

Upvotes: 0

Related Questions