Search code examples
djangoobjectviewparent

Django: check if the object has a parent and a grandparent


I'm developing a website with a 3-level hierarchy of pages, so each page may have a parent and a "grandparent" (actually, a parent of parent) page. In my PageUpdateView I have a get_success_url, which should return different URLs, depending of, whether the page has a parent and a grandparent, such as: "/grandparent/parent/page/", "/parent/page/", or "/page/". So, I need to check if a page has a parent and a grand parent. I have tried such a way:

def get_success_url(self):
    if self.object.parent.parent:
        return reverse('about:detail', kwargs={'grandparent': self.object.parent.parent.slug, 'parent': self.object.parent.slug, 'page': self.object.slug })
    elif self.object.parent:
        return reverse('about:detail', kwargs={'parent': self.object.parent.slug, 'page': self.object.slug })
    else:
        return reverse('about:detail', kwargs={'parent': self.object.parent.slug, 'page': self.object.slug })

Also, I've tried to make a condition:

if self.object.parent.parent.exists

But every time I get an Error: 'NoneType' object has no attribute 'parent' or 'NoneType' object has no attribute 'exist'.

Please give me a hint how to check if an object has a parent and a grandparent.


Solution

  • If there is no parent, then self.object.parent is None, and this has no .parent.

    You thus should only check if it has a grandparent, if it at least has a parent, so:

    def get_success_url(self):
        parent = self.object.parent
        if parent:
            grandparent = parent.parent
            if grandparent:
                return reverse(
                    'about:detail',
                    kwargs={
                        'grandparent': grandparent.slug,
                        'parent': parent.slug,
                        'page': self.object.slug,
                    },
                )
            else:
                return reverse(
                    'about:detail',
                    kwargs={'parent': parent.slug, 'page': self.object.slug},
                )
        else:
            return reverse('about:detail', kwargs={'page': self.object.slug})

    For the last one, since there is no parent, we can only put the page on the context of the URL reversing, not its parent.