PageView

Django Tips #5 How to Merge QuerySets

Django Tips #5 How to Merge QuerySets (Picture: https://www.flickr.com/photos/37930382@N05/5055991764/)

This tip is particularly useful when you want to merge two or more querysets into a single queryset without losing the capabilities of performing filter, count, distinct, etc. operations.

Consider the following models:

class Story(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField(blank=True)
    category = models.ForeignKey(Category, related_name='stories')
    author = models.ForeignKey(User, related_name='stories')

class Medium(models.Model):
    name = models.CharField(max_length=30, unique=True)
    stories = models.ManyToManyField(Story)

Let’s say you want to display all the stories published in a specific Medium together with stories written by a User using the Category django. Note that this User might have published stories in different Medium:

medium = Medium.objects.get(name='Django Blog')
user = User.objects.get(username='vitor')

django_stories = medium.stories.all()
vitor_stories = user.stories.filter(category__name='django')

At this point we have two different querysets, one containing all the stories from a medium and other containing all the stories from a user using the django category.

The querysets can be merged like in the example below, using the | operator:

stories = django_stories | vitor_stories  # merge querysets

And you still can perform queryset operations:

recent_stories = stories.distinct().order_by('-date')[:10]

It’s important to note that the merge/combine operator | only works on querysets from the same model and before the slicing it.