# Class-Based TemplateTags (POC)

**URL:** <https://forum.djangoproject.com/t/class-based-templatetags-poc/35869>\
**Category:** Show & Tell\
**Created:** [October 22, 2024, 6:25pm UTC](https://forum.djangoproject.com/t/class-based-templatetags-poc/35869 "2024-10-22T18:25:07Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![emma](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/emma/32/21174_2.png) [@emma](https://forum.djangoproject.com/u/emma)\
**Post date:** [October 22, 2024, 6:25pm UTC](https://forum.djangoproject.com/t/class-based-templatetags-poc/35869/1 "2024-10-22T18:25:07Z")

</div>

Lately I’ve been writing more Django template tags than usual and last Thursday morning, I spotted a [Mastodon Thread](https://social.joshthomas.dev/@josh/113320955214591905) 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](https://django-templateyak.levit.be)  
Blog article: [Django TemplateYaks](https://emma.has-a.blog/articles/django-template-yaks.html)

---

<div class="post-metadata">

**Author:** ![emma](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/emma/32/21174_2.png) [@emma](https://forum.djangoproject.com/u/emma)\
**Post date:** [October 22, 2024, 6:33pm UTC](https://forum.djangoproject.com/t/class-based-templatetags-poc/35869/2 "2024-10-22T18:33:45Z")

</div>

I forgot to mention that I’m looking for feedback 🙂

---

<div class="post-metadata">

**Author:** ![adamchainz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/adamchainz/32/26_2.png) [@adamchainz](https://forum.djangoproject.com/u/adamchainz)\
**Post date:** [October 22, 2024, 8:37pm UTC](https://forum.djangoproject.com/t/class-based-templatetags-poc/35869/3 "2024-10-22T20:37:13Z")

</div>

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](https://github.com/django/django/pull/18343) . 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?

---

<div class="post-metadata">

**Author:** ![emma](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/emma/32/21174_2.png) [@emma](https://forum.djangoproject.com/u/emma)\
**Post date:** [October 23, 2024, 8:42am UTC](https://forum.djangoproject.com/t/class-based-templatetags-poc/35869/4 "2024-10-23T08:42:12Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![emma](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/emma/32/21174_2.png) [@emma](https://forum.djangoproject.com/u/emma)\
**Post date:** [October 23, 2024, 6:00pm UTC](https://forum.djangoproject.com/t/class-based-templatetags-poc/35869/5 "2024-10-23T18:00:50Z")

</div>

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](https://gitlab.levitnet.be/emma/django-yak/-/blob/main/yak/utils.py#L84)

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](https://gitlab.levitnet.be/emma/django-yak/-/blob/main/yak/utils.py#L26)

An exploration of multiple ways to rewrite a few of Django’s builtin tags: [yak/templatetags/django\_yak.py · main · Emma / Django YAK · GitLab](https://gitlab.levitnet.be/emma/django-yak/-/blob/main/yak/templatetags/django_yak.py)

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

---

<div class="post-metadata">

**Author:** ![boxed](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/boxed/32/11975_2.png) [@boxed](https://forum.djangoproject.com/u/boxed)\
**Post date:** [October 24, 2024, 12:22pm UTC](https://forum.djangoproject.com/t/class-based-templatetags-poc/35869/6 "2024-10-24T12:22:30Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![emma](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/emma/32/21174_2.png) [@emma](https://forum.djangoproject.com/u/emma)\
**Post date:** [October 24, 2024, 12:34pm UTC](https://forum.djangoproject.com/t/class-based-templatetags-poc/35869/7 "2024-10-24T12:34:51Z")

</div>

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](https://github.com/django/django/blob/main/django/template/library.py#:~:text=bits)

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 not`as` or `with`) is in the realm of “advanced” usage and therefore kept the term most “advanced templataggers” would already be familiar with
