Day 23 Dev Notes

Once again, my AI friend has helped me out in a really unexpected and amazing way. For the last few nights, I've been adding new template tags to access various elements of the Post. My thinking is that you shouldn't need to know the field names of the model, you should just be able to type {% post_author %} to get the author, or, {% post_date %} to get the date.

But up until now, I thought that the only way I could do this, was to pass the Post object as the parameter so that the template tag knew which post author or date we're wanting. So the code ended up looking this: {% post_author post %} to get the author, or {% post_date post %} to get the date.

So I asked ChatGPT if there was a way to automatically get the Post object from the template tag, and to my surprise, this ended up being a simple and beautiful solution. I should point out that I didn't really like the first suggestion that ChatGPT made, which was to use a context manager to add the Post object to the context if there was a post_id in the GET request. So I pushed back on that suggestion, and the next one was much simpler and suited my use case perfectly.

The suggestion was to add takes_context=True to the decorator, which gives me access to the context of the view. Then I can check if there's a Post object in the context and display what I need. The template tag changes to exactly what I want it to be: {% post_author %}, and while the template tag code is slightly longer, it's still perfectly readable and makes sense.

Here's the original template tag (type hints and docstrings removed for brevity):

@register.simple_tag
def post_author(post):
    author = post.author
    author_display_name = get_author_display_name(author)

    return mark_safe(f'<span rel="author">{author_display_name}</span>')

And here's what it looks like afterwards:

@register.simple_tag(takes_context=True)
def post_author(context) -> str:
    post = context.get("post")
    if not post:
        return ""

    author = post.author
    author_display_name = get_author_display_name(author)

    return mark_safe(f'<span rel="author">{author_display_name}</span>')

And here's one example of how I can use the following simple code in my templates:

<p>Posted on {% post_date %} by {% post_author %}</p>

Extremely happy with this solution. In fact, I was so happy with I refactored all the template tags to use this and ended up staying up much later than planned. Learned something new today!

GitHub Link