Class-Based TemplateTags (POC)

Lately I’ve been writing more Django template tags than usual and last Thursday morning, I spotted a Mastodon Thread about Django templates and composability.

This sent me down a bit of a rabbit hole and I wrote a proof-of-concept library for writing class-based templatetags. It provides developpers with all the tools used by simple_tag and inclusion_tag so one doesn’t have to rewrite things like token parsing every time they need to write an advanced template tag, and more.

Docs: https://django-templateyak.levit.be
Blog article: Django TemplateYaks

2 Likes

I forgot to mention that I’m looking for feedback :slight_smile:

1 Like

Thanks Emma, this is a nice experiment. I like the renewed energy being put into DTL right now.

I can see the motivating case, and I like how the blog post carries on from the Mastodon thread, which I missed. Btw, looks like Django 5.2 should have simple_block_tag to ease creation of content-capturing tags: Fixed #35535 -- Add simple block tag by RealOrangeOne · Pull Request #18343 · django/django · GitHub . Still doesn’t have the “slot” mechanism your tags provide, which I like.

The docs and blog post would be easier to understand with usage examples for the various tags, like how the simple “hello” tag can be used as {% hello %} (I think?).

I am not sure I like the “one base class” approach. Inheriting from TemplateTag and switching between simple/inclusion/block tags by changing which methods/attributes you implement seems a bit harder to operate than having different base classes. It also makes them hard to type check or otherwise verify. For example, if I misspell template_name for an inclusion tag, afaik that will revert the tag to being a simple tag, causing an error due to render() returning the wrong type.

Overall, great experiment. I will keep it in mind for when I’m next writing some tags.

Maybe a next step would be to see if a class-based approach could simplify any of the tags within Django?

1 Like

Thanks for the feedback Adam.

looks like Django 5.2 should have simple_block_tag

Yes, Jake told me about it. I’m glad it’s going to be in 5.2.
But it doesn’t really help with the complexity underlying those Library methods that all look very similar. It also only helps a subset of people trying to build more complex tags.

The docs and blog post would be easier to understand with usage examples for the various tags, like how the simple “hello” tag can be used as {% hello %}

Good point, I’ll add those.

I am not sure I like the “one base class” approach

I’m not sure that’s a requirement either… I can see the point about type checking. And I don’t see any reason not to have a set of specialized classes that inherit from TemplateTag and set some constaints, like setting a node_class attribute to override the property of the same name.

I know that one of the major complaints about class-based views is the lasagna architecture of mixins, so I’d still rather have that TemplateTag class as a “complete” base and restrict the behaviour in subclasses rather than the other way around.

Maybe a next step would be to see if a class-based approach could simplify any of the tags within Django?

What do you suggest as the way to do that? A diff?

Since I was not sure what you were asking for exactly, I did multiple things here…

A simple monkey-patch to reduce repetition of code in django.library.Library (no cbtt): yak/utils.py · main · Emma / Django YAK · GitLab

A full on monkey-patch in the same library that would ensure backwards compatibility but uses cbtt for everything (including the incoming simple_block_tag and block_inclusion_tag: yak/utils.py · main · Emma / Django YAK · GitLab

An exploration of multiple ways to rewrite a few of Django’s builtin tags: yak/templatetags/django_yak.py · main · Emma / Django YAK · GitLab

Note that tags like if and for would not be possible to port tight now as yak would need some sort of “else_nodelist(s)” , which is a thing I’ve poundered but not implemented at this stage.

Also, if you’re going where I think you’re going (this not being just a library but a replacement for the current templatetags) I don’t think all existing tags need to be re-written

clean_bits surprised me as a name. Why isn’t it like… process_tokens or something?

Short answer: Django

This is how it’s referred to inside DTL in most places django/django/template/library.py at main · django/django · GitHub

I debated about using something more meaningful but then everyone who’s used to digging in would be confused. I reasoned that using custom arbitrary strings (ie notas or with) is in the realm of “advanced” usage and therefore kept the term most “advanced templataggers” would already be familiar with

2 Likes