Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to get Django QuerySet 'exclude' to work right?
    primarykey
    data
    text
    <p>I have a database that contains schemas for skus, kits, kit_contents, and checklists. Here is a query for "Give me all the SKUs defined for kitcontent records defined for kit records defined in checklist 1":</p> <pre><code>SELECT DISTINCT s.* FROM skus s JOIN kit_contents kc ON kc.sku_id = s.id JOIN kits k ON k.id = kc.kit_id JOIN checklists c ON k.checklist_id = 1; </code></pre> <p>I'm using Django, and I mostly really like the ORM because I can express that query by:</p> <pre><code>skus = SKU.objects.filter(kitcontent__kit__checklist_id=1).distinct() </code></pre> <p>which is such a slick way to navigate all those foreign keys. Django's ORM produces basically the same as the SQL written above. The trouble is that it's not clear to me how to get all the SKUs <em>not</em> defined for checklist 1. In the SQL query above, I'd do this by replacing the "=" with "!=". But Django's models don't have a not equals operator. You're supposed to use the exclude() method, which one might guess would look like this:</p> <pre><code>skus = SKU.objects.filter().exclude(kitcontent__kit__checklist_id=1).distinct() </code></pre> <p>but Django produces this query, which isn't the same thing:</p> <pre><code>SELECT distinct s.* FROM skus s WHERE NOT ((skus.id IN (SELECT kc.sku_id FROM kit_contents kc INNER JOIN kits k ON (kc.kit_id = k.id) WHERE (k.checklist_id = 1 AND kc.sku_id IS NOT NULL)) AND skus.id IS NOT NULL)) </code></pre> <p>(I've cleaned up the query for easier reading and comparison.)</p> <p>I'm a beginner to the Django ORM, and I'd like to use it when possible. Is there a way to get what I want here?</p> <p>EDIT:</p> <p>karthikr gave an answer that doesn't work for the same reason the original ORM .exclude() solution doesn't work: a SKU can be in kit_contents in kits that exist on <em>both</em> checklist_id=1 and checklist_id=2. Using the by-hand query I opened my post with, using "checklist_id = 1" produces 34 results, using "checklist_id = 2" produces 53 results, and the following query produces 26 results:</p> <pre><code>SELECT DISTINCT s.* FROM skus s JOIN kit_contents kc ON kc.sku_id = s.id JOIN kits k ON k.id = kc.kit_id JOIN checklists c ON k.checklist_id = 1 JOIN kit_contents kc2 ON kc2.sku_id = s.id JOIN kits k2 ON k2.id = kc2.kit_id JOIN checklists c2 ON k2.checklist_id = 2; </code></pre> <p>I think this is one reason why people don't seem to find the .exclude() solution a reasonable replacement for some kind of not_equals filter -- the latter allows you to say, succinctly, exactly what you mean. Presumably the former could also allow the query to be expressed, but I increasingly despair of such a solution being simple.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload