Django FilteredRelation


Django / Wednesday, December 6th, 2017

Overview
FilteredRelation() comes from Django 2.0. It helps to make the query faster than the filter in some cases. Suppose you have Blog posts. Now you want to filter out all the published posts who have author name, John. 

FilteredRelation(relation_name, condition=Q())
Here,
relation_name is the field that you want to filter.
condition=Q() accept filtering object. Django prefer Q() to handle that operation.

FilteredRelation() is used annotate() to handle filtering. Basically, it uses ON clause when JOIN is necessary.

Model Example,

class Post(models.Model):
    author = models.ForeignKey(Author)
    publication_status = models.IntegerField(default=0) # 0 = Draft, 1 = Publish, 2 = Archieve
    ... ...

Example of FilteredRelation()

from django.db.models import FilteredRelation, Q

Post.objects.annotate(
    filtered_posts=FilteredRelation(
        'author', condition=Q(status=1),
    ),
).filter(filtered_posts__name__iexact='John')

If there is a big amount of posts then above code will be faster than the below. Using,FilteredRelation() on first code, it used only one WHERE clause when .filter(filtered_posts__name__iexact='John')

Post.objects.filter(
    author__status=1,
    author__name__iexact='John'
)

Note: It doesn’t support on nested relations. For example, author may have a foreign key with role. So, in this case, we can’t use author__role. Example below,

Post.objects.annotate(
    filtered_posts=FilteredRelation(
        'author__role', condition=Q(status=1),
    ),
).filter(filtered_posts__name__iexact='John')

You have look at these,

 

Leave a Reply

Your email address will not be published. Required fields are marked *