Building your own template tags in django
Tags: django, python
Published: 2020-03-01 15:36:08

Hey Guys !

Well, in a previous blog i wrote about [creating your own context variable](https://dev.to/harveyhalwin/using-context-processor-in-django-to-create-dynamic-footer-45k4). To take that a step further, why don't we create our own template tags. So, what is a template tag ? It is a built-in django function that returns an output.

Now, you might have some doubts as to why you would need a template tag instead of a context variable, since, they're both functions and they both return a value. Right? Well, if that thought didn't come to mind, the reason for creating your own template tag is that, you can actually **pass a value** to the function upon which you could do your processing, while you could not with the context variable.

#Why and Where do you need your own template tags

Before we go and create our own template tags, first, you need to look in the django official documentation, there's a high probability that the template tag that you're looking for might be in there.

In this blog, i will consider my project to be an online shopping app and my models will include the products on sale and the corresponding reviews on those products. So, my models.py file will look like this.

```python
from django.db import models
from django.contrib.auth.models import User

class Product(models.Model):
    name = models.CharField(max_length=50)
    description = models.CharField(max_length=200)
    sold_by = models.ForeignKey(User)
    price = models.IntegerField()

    def __str__(self):
        return self.name


class Review(models.Model):
    content = models.CharField(max_length=100)
    reviewed_on = models.ForeignKey(Product)
    reviewed_by = models.ForeignKey(User)

    def __str__(self):
        return self.content
```

So, in my product listing page, i want to be able to view the products and the review count for each product there. You could write a ORM query for it in your *views.py* file but what if you need the same count in each of the dedicated product pages, you would have to repeat that code. Unless, you had a function which accepts the product id and returns the count of reviews of that specific product. You could use that function anywhere. This function is our template tags and we will be using it to solve this problem.

#Creating your own template tags using the simple_tag

First, you need to create a folder inside your app called *templatetags* and create a file named *\__init\__.py* . This will initiliase our templatetags folder as a python package, basically, django will consider it as part of its own project folder architecture.

Secondly, lets create a python file with any name, for this blog, i'll name it *product_tags.py*. Now, we are going to be creating our own template tags using the simple_tag.

```python
from django import template
from your_app.models import Product, Review

register = template.Library()

@register.simple_tag
def calc_review_count(product_id):
    product = Product.objects.get(id=product_id)
    reviews = Review.objects.filter(reviewed_on=product)
    return reviews.count()
```


#Using our custom template tags in our templates

Now, your template tags is ready to be used in your html files. So lets create a ListView pretty quickly in my *views.py* file.

```python
from django.views.generic import ListView
from .models import Product


class ProductListing(ListView):
    template_name = 'product_list.html'
    model = Product
    context_object_name = 'products'
```

Finally, lets go ahead and create our html file that i named *product_list.html*.

```html
{% load product_tags %}  <!-- Loading the file we defined our template tags in -->

<div>
    <table>
        <thead>
             <tr>
                  <th>Name</th>
                  <th>Price</th>
                  <th>Sold By</th>
                  <th>Reviews</th>
             </tr>
        </thead>
        <tbody>
            {% for pdt in products %}
             <tr>
                  <td>pdt.name</td>
                  <td>pdt.price</td>
                  <td>pdt.sold_by</td>
                  <td>{% calc_review_count pdt.id %}</td> <!-- our template tag -->
             </tr>
             {% endfor %}
        </tbody>
    </table>
</div>
```

Now, in a url that you configured, our template will show us the product listing and the review count for each of those products. **Do note that we do not need closing template tags for template tags created using the simple_tag.**

So what did you think about creating your own template tags ? Where do you think, you can use this ? Let me know.

Thanks and Have a Great Day !