Opened 9 years ago
Closed 8 years ago
#25754 closed Bug (invalid)
Queryset repr is not displayed on IPython >= 3.0 REPL if a NotImplementedError is raised
Reported by: | Michael Angeletti | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | distinct |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I'm running SQLite3 , and the following doesn't result in an error or any visible output:
In [5]: Spam.objects.distinct('field') Out[5]: In [6]: isinstance(Spam.objects.distinct('field'), models.QuerySet) Out[6]: True
The queryset is not evaluated for some reason.
In [7]: repr(Spam.objects.distinct('field')) --------------------------------------------------------------------------- NotImplementedError Traceback (most recent call last) ... NotImplementedError: DISTINCT ON fields is not supported by this database backend
Maybe this bug is really "queryset not evaluated when it should be", rather than "doesn't raise an error when it should", since the following is evaluated as expected:
In [8]: Spam.objects.all() Out[8]: [<Spam: Salty>, <Spam: Delicious>, <Spam: Goo>]
Change History (14)
comment:1 by , 9 years ago
comment:2 by , 9 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
Hi yoyoma,
As you might know QuerySet
are lazily evaluated.
In this case Django needs to determine which backend will be used to run the query against (e.g. routers can be involved) before raising the NotImplementedError
. That's the reason why the error will only be raised at execution time.
comment:3 by , 9 years ago
Hi charettes,
I appreciate the quick response, but I'm afraid you didn't read the entire report. The queryset, in the context I've given, should have been evaluated. See the first line of code in the first example.
Take for instance, the example from https://docs.djangoproject.com/en/1.8/topics/db/optimization/#understand-cached-attributes:
>>> entry = Entry.objects.get(id=1) >>> entry.authors.all() # query performed >>> entry.authors.all() # query performed again
Placing a queryset directly into the REPL should result in evaluation.
comment:4 by , 9 years ago
What's the definition of your Spam
model?
When I try to do Spam.objects.distinct('field')
, I get the NotImplementedError
(as expected).
Doing the isinstance()
check however doesn't evaluate the queryset but that seems like the expected behavior to me.
comment:5 by , 9 years ago
bmispelon,
Correct. Running isinstance(queryset)
should NOT evaluate the queryset. However, placing queryset
directly into the shell should (e.g., the example that you said you tried - what version of Django/Python/ipython are you running?).
The following was actually copy/pasted from my shell, this very moment:
In [4]: Answer.objects.distinct('text') Out[4]: In [5]: Answer.objects.distinct('query') Out[5]: In [6]: type(Answer.objects.distinct('query')) Out[6]: django.db.models.query.QuerySet
Does that even look normal? Of course not. Unless an expression is None
, its shell representation is usually visible.
My model looks exactly like this:
class Answer(models.Model): created_at = models.DateTimeField( _('created at'), default=timezone.now, editable=False ) updated_at = models.DateTimeField(_('updated at'), auto_now=True) query = models.ForeignKey('queries.Query', verbose_name=_('query')) text = models.TextField(_('text'))
There isn't a custom manager.
comment:6 by , 9 years ago
Resolution: | invalid |
---|---|
Status: | closed → new |
It looks like I skimmed through the report a bit too fast.
comment:7 by , 9 years ago
I'm using Django 1.8.6 and I tried with both Python 3.5.0 and 2.7.10 (plain python shell).
I've also tried using the same model as you and I see the NotImplementedError
(as expected).
comment:8 by , 9 years ago
I do observe the same behavior as you when I install IPython though.
My guess is that IPython is doing weird things with QuerySet.__repr__
. Not sure if that's a Django bug though...
comment:9 by , 9 years ago
I can reproduce with IPython 4.0.0 but not with 2.3.1. Looks like the issue might be there.
comment:10 by , 9 years ago
From testing different versions it looks like this behavior was introduced by IPython 3.0.0
comment:11 by , 9 years ago
It looks like NotImplementedError
are treated differently from other exceptions since IPython 3.0.0
In [1]: class Foo(object): ...: def __repr__(self): ...: raise Exception ...: In [2]: Foo() ... traceback In [3]: class Foo(object): def __repr__(self): raise NotImplementedError ...: In [4]: Foo() Out[4]:
comment:12 by , 9 years ago
charettes,
Thanks for looking into this. I decided to page through the 3.0 release issues (55 pages!) on GitHub, searching each page for "exception". Perhaps a Google search would have been easier, but I found the following:
I haven't had a chance to look through them completely (gotta run some errands), but I wanted to add them in the meantime.
comment:13 by , 9 years ago
Summary: | queryset.distinct('field') doesn't raise "DISTINCT ON not supported" when it should → Queryset repr is not displayed on IPython >= 3.0 REPL if a NotImplementedError is raised |
---|---|
Triage Stage: | Unreviewed → Accepted |
Version: | 1.8 → master |
Thanks for the investigation yoyoma.
I'm unsure about what should be done here. IMO IPython is trying to be too smart here by swallowing the NotImplementedError
but I'm tentatively accepting until we figure it out.
comment:14 by , 8 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
I don't think Django can do anything about it. Relevant commit in ipython.
I'm running the following:
Python 3.4.3