tom
tom

Reputation: 2365

Pythonically filter Django queryset based on lack of reverse relationships

Suppose I have two Django models, let's say Product and Manufacturer, and wish to find Manufacturers who have no Products.

class Product(Model):
    name = models.CharField()
    manufacturer = models.ForeignKey(Manufacturer)
class Manufacturer(Model):
    name = models.CharField()

I want to generate a set of all Manufacturer objects that are not referred to by any Product objects. I can think of many ways to get this set, but none of them seem clean or Pythonic

  1. Given the queryset of all Products, generate a set of all Manufacturers that have products. Then take the set difference of all manufacturers with the manufacturers_with_products as described here: How to get the difference of two querysets in Django.
  2. Filter the Manufacturer objects based on the lack of a reverse relationship with any Products. Django makes it easy to filter based on properties of reverse relationships, but I cannot find a clean way to filter based on the existence of this reverse relationship.

eg, I can trivially filter Manufacturers that have at least one Product that satisfies a condition:

models.Manufacturer.objects.filter(product__name=x)

I'd like to be able to filter something more like

models.Manufacturer.objects.exclude(product__exists)

I could probably exclude/filter Manufacturers on some axiom/tautology of Products, but that also doesn't seem very Pythonic.

Upvotes: 3

Views: 288

Answers (1)

user764357
user764357

Reputation:

This can be done using an annotation and a filter:

from django.db.models import Count
idle = Manufacturers.objects.annotate(num_products=Count('product')).filter(num_products=0)

idle will the contain a list of Manufacturers who have no products, but keep in mind they will also have a property num_products, which due to the query will be 0.

Upvotes: 2

Related Questions