Search code examples
djangodjango-modelsmany-to-many

Django recursive query on non-symmetrical Many-to-Many to the same model


I'm offering services to companies (many-to-many between Service and Company). To structure my services, I use a tree-like structure using Django's many-to-many field. So, a service can contain multiple other services.

The question: how can I retrieve all services a company has? Using company.services, I only get the services directly related to that company. I need the directly related ones + included_services (in a recursive way).

class Company(models.Model):
    services = models.ManyToManyField(Service)

class Service(models.Model):
    name = models.CharField(max_length=255)
    included_services = models.ManyToManyField("self", blank=True, symmetrical=False)

Solution

  • I don't think you can do this using Django's ORM framework or writing a plain raw SQL statement. You might want to take a look at 3rd party libraries like django-mptt that enables you to store/retrieve models represented in tree-like structures more efficiently.

    However, if you want to do it via Python, here is what you can do:

    def get_services(company):
        services = list(company.services.all())
        result = []
        while services:
            service = services.pop(0)
            result.append(service)
            services.extend(list(service.included_services.all()))
        return result
    

    The above idea is very similar to performing a breadth-first search in a tree.