How to simply create custom filters in Django
Tags: django, python, webdev, filters
Published: 2022-12-04 16:11:58

Django template system, allows for the use and creation of custom filters. Using custom filters is a powerful feature that allows the developer to bend the templating system to do things other than already defined. 

For instance, you could develop a custom filter to return a lookup value once applied to a field ID.

You can find more information on the Official [Django Documentation website](https://docs.djangoproject.com/en/4.1/howto/custom-template-tags/)

Extending your template tags with custom filters offers flexibility in your code. 
----

#### Assumptions


This tutorial assumes a basic understanding of Django and Python. The project also assumes that a basic Django app has been setup already.

Keep in mind filters are functions. So a good understanding of python functions is required.
----

*What our app will do?*

The app will store students’ names and their classroom

*What our filter will do?*

We will define two filters: `number_of_students_filter` and `classroom_of_students`
----

#### Step 1


To define your template filters or tags you need to create a subfolder with the name `templatetags` in your app folder.

Add the `__init__.py` into your folder to render it as a module. Latest versions of python do not require this. 

For example given an app named `students` you could have this folder structure:

```python
students/
	templatetags/
		__init__.py
		student_filters.py
		
```


The file name of the file to contain out custom filters is named `student_filters.py`
----

#### Step 2: Lets build our filters


Open the file `student_filters.py` :

Our first filter will be named number_of_students_filter. 

```python
def number_of_student_filter(value):
	
	if value

	return number_of_students
	
```


#### Walkthrough


The above function like any other filter takes in an argument value. The value is the parameter that comes before the use of the pipe | symbol when writing tags with filters

`{{ var | filter }}`

Therefore, the value is var in this case. In the body of the function, you define what the filter must do, you can do anything but you cannot throw exceptions as filters can output them by design. 

In this function, we return the number of students in our students’ table by chaining our query with the `count()` method. 
----

#### Step 3


The function will now have to be registered as a filter. Django offers a simple interface for this. 

Near the top of your file, place the following:

```python
from django import template

register = template.Library()
```


#### Walkthrough 


It is required that for a valid library tag, the file/module must contain a variable named `register` which must be an instance of the `templated.Library` class. 

To register the filter there are two major ways; using the register function itself or as a decorator. 

#### `register` as a function approach


`register.filter('number_of_students`’`, number_of_students)`

This takes two arguments, the first argument is the name of the filter and the second argument is the filter function itself.

#### `register` as a decorator approach


```python
@register.filter(name='number_of_students') 
def number_of_students_filter(value):
	
	number_of_students = Students.objects.all().count()

	return number_of_students
```

----

#### Step 4


Now, you just need to load the module, in this case, `student_filters` it in your template file. This is done just like the way you load `static`, however in this case you load it with the name of the file/module that contains the filters. In our scenario `{{ load student_filters }}` .

```html
{{load student_filters }}

<!DOCTYPE>
<html>
	<title>Custom Filters</title>
	<body>
	
	<h1>Students</h1>
	<h2>Number of {{ students|number_of_students }}</h2>
	
	
	</body>
</html>
```


#### Adding arguments to the filter


`{{ var | classroom_of_students: 40}}`

Now, how about we allow our custom filter to accept an argument, say `arg`. But we’ll create a new custom filter and name it `classroom_students_are_in_filter`. This filter will take a number as an argument and based on that number indicate whether by number of students; they are in a larger classroom or not.

```python
@register.filter(name='classroom_of_students') 
def classroom_students_are_in_filter(value, arg):
	
	number_of_students = Students.objects.all().count()
	
	if number_of_students > arg:
		return 'Students are in the larger classroom'
	elif number_of_students < arg:
		return 'Students are in the smaller classroom'

```


Walkthrough

This filter classroom_of_students takes an arg, the argument is what appears after the colon when placed in a template. This argument can be anything, string, float, integer etc. In this case it is an integer. Then run what you would like to do in the body of the function.

Don't forget to register the filter.

Voila!