Pages - parent & child - impact in paths/slugs

Let’s imagine a simple “page” system where:

  • a page is defined/written in the admin
  • a page can have a parent page (optional)

How would you go about:

  • writing the right urls.py to handle browser-side paths, such as page_slug/page_slug/page_slug?
  • where the template call {% url 'page' slug='this-is-a-slug' %} would actually be modified to include in its output the parent pages slugs (thus generating the abve)?

I think it is a two-way problem:

  • handle proper path generation (via a new template tag maybe?) for the template
  • handle proper server-side url matching (via a re_path instead of a simple path)

Thanks!

I’m not sure I fully understand what you’re trying to achieve here.

You wrote:

Is this a full hierarchical structure? In other words, can a “parent page” itself also have a parent page? How deep can these pages be nested?

Why would you want, or need, to contain the full chain of slugs in your url?

Specifically, if this is a full, unbounded hierarchical structure, you’d want to organize your database as to facilitate retrieval of this data.

We use, are very happy with, and can easily recommend Django treebeard for creating the appropriate models for this structure.

That would seem to me to be a lot better than trying to manage those relationships through urls.

Hi Ken,

Thanks for replying.

To answer your questions:

  • yes it is a full hierarchical structure, so no limit to the depth apart from common sense (it is content supposed to be easily browsable by a human, so at the most 3 or 4 levels deep)
  • I want to limit the level of dependency with regards to third-party packages (I know it’s too late xD I am a heavy django fan/user).

But I managed something quite nice. Here goes:

In urls.py (see URL dispatcher | Django documentation | Django):

    path(
        '<path:path>',
        PageView.as_view(),
        name='page'
    ),

The “full path” is generated at model level, something similar to the following pseudo code:

page.get_parents()
page.get_parents_path()
page.generate_full_path)

Which returns something similar to top-level-page/intermediate-page/the-current-page.

Matching is done at view level, with again something similar to:

path = self.kwargs['path']
path_list = path.split('/')
slug = path_list.pop()
try:
    Page.objects.get(slug=slug)
except Page.DoesNotExist:
    raise HTtp404

At template level, I have indeed create a template tag:

{% load page_url %}

{% page_url page=page %}
or
{% page_url slug='the-slug_i-want' %}

Works quite well and is quite light. My only regret is not being able to do that via a regex using a re_path or a converter.

What do you think?

If it works for you, great. I’m all in favor of simple solutions when a simple solution is sufficient for the known and projected needs.

The issue here is that this solution doesn’t scale.

At some point of size and depth, the performance is going to start to degrade. Whether or not you are ever going to reach that point is not a question I’m able to answer.

yes I do realise the “scale” issue. But those page entities will never exist in numbers above even a few hundred. With depths (again) probably never reaching 4 (it’s a functionally quite flat ensemble of pages)
Object-level and template-side caching can also help (and actually do already).