Custom admin-defined URLs in Django

One of the most useful features of Django is the graphical admin interface. The ability to edit your models visually, and without having to manually create that admin for each project is priceless.

The first thing I thought about when I learned about the admin interface was to be able to dynamically add pages to my site. Of course, this is doable, but the admin interface was created for generic model editing, not page management. And even if you do so, the URL schemes in Django are hardcoded in urls.py, right? We would need a bit of a setup to accomplish having custom admin-defined URLs.

Model

We would need a model for representing each page.

class Page(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField()
    slug = models.SlugField(max_length=100, unique=True)

    def __str__(self):
        return self.title
models.py

The interesting thing here is the slug field. A useful definition from SO:

Slug is a URL friendly short label for specific content. It only contains Letters, Numbers, Underscores, or Hyphens.

So, for example, a page about black coffee variants should be reachable at www.example.com/black-coffee-variants. The slug here is black-coffee-variants.

You could potentially auto-generate the slug from another piece of data, the title for instance, but I prefer to set it manually to have maximum control.

Finally, don't forget to register the model in the admin interface.

admin.site.register(Page)
admin.py

View

You would need a view that accepts the slug as a parameter and queries for the appropriate model.

def my_page(request, slug):
    context = {
        'page': get_object_or_404(Page, slug=slug)
    }
    return render(request, 'page.html', context)
views.py

Since we defined in the model that the slug field is unique, we can use that as an identifier for the page.

URLs

Finally, to bind them all together, you would need to define a URL pattern for your model.

urlpatterns = [
    path('', views.index, name='index'),
    path('<slug:slug>/', views.my_page, name='my_case'),
]
urls.py (app)

Any detected slug will result int the calling of your my_page() method we defined earlier.

Admin

Head to your admin interface and add a few pages. You can access them by the defined slug, with no changes to your urls.py. Happy page editing!