4

I have the following models (resumed) in an application:

class Account(models.Model):
    name = models.CharField(max_length=64)
    plans = models.ManyToManyField('Plan')
    extra_services = models.ManyToManyField('Service')

class Plan(models.Model):
    name = models.CharField(max_length=64)
    services = models.ManyToManyField('Service')

class Service(models.Model):
    name = models.CharField(max_length=64)

Plan here is just an aggregation of services, but an account may have separate services. In admin (Account) I want to show a select box with all Services (extra_services) that AREN'T TIED with any Plan. What's the best queryset I can use to get this (in limit_choices_to)?

PS: I don't want to iterate over all Plans to get all the Services ids that are linked and after that exclude them in a filter.

lmlf
  • 111
  • 4

2 Answers2

4

Service.objects.filter(plan_set__isnull=True) should do.

You may find further explanation in the documentation.

Michal Chruszcz
  • 2,452
  • 16
  • 20
  • Are you sure? I had already tried this, but with no luck (always get something like: FieldError: Cannot resolve keyword 'plan_set'). I can do this in the oposite way: Plan.objects.filter(services__isnull=True). – lmlf Mar 18 '11 at 12:30
  • 2
    I don't remember exactly right now, but you may always provide the `related_name` in your `Plan` model, e.g. `services = models.ManyToManyField('Service', related_name='plans')` and then query services using `Service.objects.filter(plans__isnull=True)`. – Michal Chruszcz Mar 18 '11 at 15:01
1

OK, I got this using a raw SQL query:

services = Service.objects.raw('SELECT * FROM accounts_service WHERE id NOT IN(SELECT service_id FROM accounts_plan_services);')

Anyway, can I do this without a raw SQL query?

lmlf
  • 111
  • 4