My non_toxic_items() method does not return the 'correct' set.

Currently,

Item.inventory.all()

returns less than

Item.inventory.non_toxic_items()

Here is my manager with the problematic method. See the explanation in the function for what I would like it to return.

#manager.py from django.db import models class InventoryManager(models.Manager): def get_queryset(self): return super(InventoryManager, self).get_queryset().filter( shipment__isnull=True, ) def non_toxic_items(self): """ Return all non-toxic items, not part of a shipment. As python code:: context['my_qs'] = [] for batch in self.object_list: flag = False for input in batch.input_set.all(): if input.material.type.is_toxic: flag=True if not flag: for item in batch.item_set.all(): if item.shipment is None: context['my_qs'].append(item) """ return super(InventoryManager, self).get_queryset().filter( # BUG -- Does not return the same queryset as above python code. shipment__isnull=True, batch__input__material__type__is_toxic=False).distinct()

And these are the models

from django.db import models from .managers import InventoryManager from shipment.models import Shipment class MaterialType(models.Model): type = models.CharField(max_length=255, ) is_toxic = models.BooleanField(default=False, ) ... class Material(models.Model): type = models.ForeignKey(MaterialType) lot_number = models.CharField(max_length=50, ) ... class Batch(models.Model): batch_number = models.IntegerField(primary_key=True, ) ... class Input(models.Model): """ These are input materials to a batch. A batch may contain at most 1 toxic material. """ batch = models.ForeignKey(Batch) material = models.ForeignKey(Material) ... class Item(models.Model): id_number = models.IntegerField(primary_key=True, ) batch = models.ForeignKey(Batch, ) shipment = models.ForeignKey(Shipment, blank=True, null=True, ) ... objects = models.Manager() inventory = InventoryManager()

I have removed all Fields which are not related to the query. The method works, but the output is incorrect...(It does not match the code in the description)

If anyone has a better solution than that expensive join, I would love to hear it.

EDIT: More details:

# imports go here class BatchListView(generic.ListView): model = Batch paginate_by = 25 def get_context_data(self, **kwargs): context = super(BatchListView, self).get_context_data(**kwargs) context['items_non_toxic'] = Item.inventory.non_toxic_items() context['my_qs'] = [] for batch in self.object_list: flag = False for my_input in batch.input_set.all(): if my_input.material.type.is_toxic: flag=True if not flag: for my_item in batch.item_set.all(): if my_item.shipment is None: context['my_qs'].append(my_item) return context

{{ my_qs }} # returns 73 items

, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 14035, 14042, 14043, 14044, 14045, 14046, 14047, 14048, 14049, 14050, 14051, 14052, 14053, 14054, 14055, 14056, 14057, 14058, 14059, 14060, 14061, 14062, 14063, 14064, 14065, 14066, 14067, 14068, 14069, 14070, 14071, 14072, 14073, 14074, 14075, 14076, 14077, 14078, 14079, 14080, 14081, 14082, 14083, 14084, 14085, 14086, 14087, 14088, 14089, 14090, 14091, 14092, 14093, 14094, 14095, 14096, 14097, 14098, 14099, 14100, ,

{{ items_non_toxic }} # returns 115 items

4, 5, 6, 7, 8, 9, 10, 11, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 10000, 10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011, 10012, 10013, 10014, 10015, 10016, 10017, 10018, 10019, 10020, 10021, 10022, 10023, 14035, 14042, 14043, 14044, 14045, 14046, 14047, 14048, 14049, 14050, 14051, 14052, 14053, 14054, 14055, 14056, 14057, 14058, 14059, 14060, 14061, 14062, 14063, 14064, 14065, 14066, 14067, 14068, 14069, 14070, 14071, 14072, 14073, 14074, 14075, 14076, 14077, 14078, 14079, 14080, 14081, 14082, 14083, 14084, 14085, 14086, 14087, 14088, 14089, 14090, 14091, 14092, 14093, 14094, 14095, 14096, 14097, 14098, 14099, 14100, 45361, 45362, 45363, 45364, 45365, 45366, 45367, 45368, 45369, 45370,