URL creation form MPTT model

I have 1 model created the uses MPTT. We have three levels to “pages” and I want to route the urls as such: https://domain.com/subject/subtopic/topic . Do I do this through coding the get_absolute_url in the model? And if so, how would I do this? If it is writing the url path, is there any help from documentation on how to do this for MPTT models? Any assistance would be greatly appreciated. Below is my model:

from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
from django.utils.text import slugify
from django.urls import reverse

class Page(MPTTModel):
id = models.IntegerField(primary_key=True)
name = models.CharField(null=True, max_length=100)
slug = models.SlugField(null=True,max_length = 100)
meta_title = models.CharField(null=True, max_length=200, blank=True)
meta_description = models.TextField(null=True, blank=True)
content = models.TextField(null=True,blank=True)
content_two = models.TextField(null=True, blank=True)
lower_content = models.TextField(null=True,blank=True)
old_url = models.CharField(max_length=255, blank=True)
new_url = models.CharField(max_length=255, blank=True, null=True,)
parent = TreeForeignKey(‘self’, on_delete=models.CASCADE, null=True, blank=True, related_name=‘children’)

class MPTTMeta:
    order_insertion_by = ['name']
    verbose_name = 'page'
    verbose_name_plural = 'pages'

def __str__(self):
    return self.name

def save(self, *args, **kwargs): # new
    if not self.slug:
        self.slug = slugify(self.slug)
    return super().save(*args, **kwargs)

def get_absolute_url(self):
        return reverse('slug', args=[str(self.slug)])

Are you saying that you want the url to be the slugs for “subject”, “subtopic”, and “topic”?

If so, then you would define an entry in your urls.py file - something like:
path('<slug:subject>/<slug:subtopic>/<slug:topic>', someview, ...)

Your view (if a function-based view) would then look something like:
def view(request, subject, subtopic, topic):
which can then retrieve the information to be displayed.

The get_absolute_url is a function you can use to build the url to retrieve an instance, but it does not do the actual routing.

Are you using the Django-MPTT package, or a different one? Whichever one you’re using, I’m sure the api has a function for retrieving all ancestors of a node. You can build the url using the output from that api.

(Side note: When posting code here, enclose the block of code between lines of three backtick - ` characters. This means you’ll have a line ```, then your code, then another line of ```. This forces the forum software to keep your code properly formatted - critical with Python.)


Thank you for your reply on this. I’m using the Django-MPTT package and I believe your answer of using the api function for retrieving the ancestors of the node is the solution I need. The defining of the path in urls.py file as with the slugs doesn’t work because the subjects, subtopics and topic are all part of the same model and defined only by the MPTT node level. I will search further for a solution with that in mind.

Thank you so much for the guidance (and the tip on posting code…newbie here).


I don’t see why that’s an issue. The url components are passed to the view. What the view does with them is entirely up to you. (I’m working under the assumption that you’re specifically wanting the 3-part url to be the url used to access an instance of Page.)

If the “topic” slug is unique, you could actually ignore the other two parts of the url.

1 Like


You are right, I could ignore the other parts but we are transferring over a 6000 page website and the url structure is with the three levels (subject/subtopic/topic). However, I think I can run a find and replace type formula in the database to find the old urls and replace them with the new one, not doing the 3 levels in the url. Thank you so much for working through this with me. Your input has been insightful and led to me to a good solution. Much appreciated!

1 Like