jazzband / jazzband/django-model-utils

'InheritanceQuerySet.instance_of' and 'count' do not mix

Open
#528 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
Python
Stars
2.8k
Forks
374
PR merge metrics
No merged PRs in 30d

Description

## Problem

When trying to use `InheritanceQuerySet.instance_of` to filter a queryset to only some sub-classes, and use `queryset.count()` to get the count, instead I get an `OperationalError`.

## Environment

- Django Model Utils version: 4.2.0
- Django version: 4.0.3
- Python version: 3.10

## Code examples

```python
from django.db import models
from model_utils.managers import InheritanceManager

class Parent(models.Model):
objects = InheritanceManager()

field = models.CharField(max_length=50)

class ChildA(Parent):
field_chield_a = models.CharField(max_length=50)

class ChildB(Parent):
field_chield_b = models.CharField(max_length=50)
```

```python
>>> for _ in range(3):
... ChildA()
... ChildB()
>>> from django.db import connection
>>> Parent.objects.instance_of(ChildA)
, , ]>
>>>Parent.objects.instance_of(ChildA).count()
Traceback (most recent call last):
File "<...>/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "<...>/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 477, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such column: playground_childa.parent_ptr_id
>>> from pprint import pprint
>>> pprint(connection.queries)
[{'sql': 'SELECT "playground_parent"."id", "playground_parent"."field", '
'"playground_childa"."parent_ptr_id", '
'"playground_childa"."field_chield_a" FROM "playground_parent" LEFT '
'OUTER JOIN "playground_childa" ON ("playground_parent"."id" = '
'"playground_childa"."parent_ptr_id") WHERE '
'(("playground_childa"."parent_ptr_id" IS NOT NULL)) LIMIT 21',
'time': '0.000'},
{'sql': 'SELECT COUNT(*) AS "__count" FROM "playground_parent" WHERE '
'(("playground_childa"."parent_ptr_id" IS NOT NULL))',
'time': '0.000'}]
```

As you can see, the query is missing the `LEFT OUTER JOIN` directive when trying to use `count`.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the reported case with InheritanceQuerySet.instance_of(ChildA).count() using the model definitions and Django, then inspect how instance_of builds the queryset and how count changes it. Confirm that the count query retains the join needed for the subclass condition and no longer raises the reported SQLite OperationalError.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
backend, databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.