Opened 10 years ago
Closed 9 years ago
#23739 closed Cleanup/optimization (invalid)
django 1.7.1 defer() throws AttributeError when using related_name
Reported by: | Farhan Ahammed | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.7 |
Severity: | Normal | Keywords: | defer related_name AttributeError RelatedObject rel |
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 have attached a simple example project, with the following Models defined:
class ModelA(models.Model): name = models.CharField(max_length=255) class ModelB(models.Model): name = models.CharField(max_length=255) model_a = models.ForeignKey(ModelA, related_name='model_b')
Entering the following code (in a Django shell) works fine:
ModelB.objects.filter(name='').select_related('model_a').defer('model_a__name')
But when I run the following:
ModelA.objects.filter(name='').select_related('model_b').defer('model_b__name')
I get this error message:
Traceback (most recent call last): File "<console>", line 1, in <module> File "/home/fahammed/Documents/django_defer_bug/venv/local/lib/python2.7/site-packages/django/db/models/query.py", line 116, in __repr__ data = list(self[:REPR_OUTPUT_SIZE + 1]) File "/home/fahammed/Documents/django_defer_bug/venv/local/lib/python2.7/site-packages/django/db/models/query.py", line 141, in __iter__ self._fetch_all() File "/home/fahammed/Documents/django_defer_bug/venv/local/lib/python2.7/site-packages/django/db/models/query.py", line 966, in _fetch_all self._result_cache = list(self.iterator()) File "/home/fahammed/Documents/django_defer_bug/venv/local/lib/python2.7/site-packages/django/db/models/query.py", line 222, in iterator only_load = self.query.get_loaded_field_names() File "/home/fahammed/Documents/django_defer_bug/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1821, in get_loaded_field_names self.deferred_to_data(collection, self.get_loaded_field_names_cb) File "/home/fahammed/Documents/django_defer_bug/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 596, in deferred_to_data cur_model = source.rel.to AttributeError: 'RelatedObject' object has no attribute 'rel'
Looks like defer doesn't work when you specify the related table using its related_name
.
Attachments (2)
Change History (9)
by , 10 years ago
Attachment: | django_defer_bug.tar.gz added |
---|
comment:1 by , 10 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Type: | Uncategorized → Bug |
comment:2 by , 10 years ago
Severity: | Normal → Release blocker |
---|---|
Triage Stage: | Unreviewed → Accepted |
This seems to be a regression present since 1.6 -- bisected to 70679243d1786e03557c28929f9762a119e3ac14. Test for Django's test suite attached.
by , 10 years ago
Attachment: | 23739-test.diff added |
---|
comment:3 by , 10 years ago
Severity: | Release blocker → Normal |
---|---|
Type: | Bug → Cleanup/optimization |
The reason pre-1.6 didn't raise exceptions was that the chunked reads implementation swallowed exceptions. I don't think there is a regression here, we just get an exception instead of silently returning empty list on error.
I tested this on Django 1.5 with the following command: [o for o in ModelB.objects.filter(name='').select_related('model_b').defer('model_b__name').iterator()]
. This raises a different error (ModelB has no field named 'model_b'), but doesn't produce any results.
We might want to allow usage of related_name
in this context, and even if we don't, users shouldn't get such an ugly error message.
comment:4 by , 10 years ago
@akaariai That's not the code that was causing the error message. From ModelB.objects.filter(name='')
, you select the related objects from ModelA and then defer the ModelA.name
value from the DB. So your command should probably be:
[o for o in ModelB.objects.filter(name='').select_related('model_a').defer('model_a__name').iterator()]
Note that ModelB
has no field called model_b
} but it does have a field called model_a
.
comment:5 by , 10 years ago
I'm confused. Using [o for o in ModelA.objects.filter(name='').select_related('model_b').defer('model_b__name')]
gives me RelatedObject has no attribute rel in 1.5. Just as it does using master. And, [o for o in ModelB.objects.filter(name='').select_related('model_a').defer('model_a__name').iterator()]
works on master.
comment:6 by , 10 years ago
I think that's because the attribute model_a
has been explicitly defined in the class definition of ModelB
, whereas the class definition of ModelA
does not have an attribute called model_b
. Correct me if I'm wrong, but the ModelA.model_b
is dynamically created at runtime (or loaded when the value is called)?
On another (possibly) similar note, calling the only()
function:
ModelA.objects.filter(name='').select_related('model_b').only('model_b__name')
also returns the same error AttributeError: 'RelatedObject' object has no attribute 'rel'
, and the following line works fine:
ModelB.objects.filter(name='').select_related('model_a').only('model_a__name')
comment:7 by , 9 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
The problem seems to be an invalid select_related()
query. On Django 1.9:
>>> ModelA.objects.filter(name='').select_related('model_b').defer('model_b__name') django.core.exceptions.FieldError: Invalid field name(s) given in select_related: 'model_b'. Choices are: (none)
You should be using prefech_related()
when querying reverse foreign keys.
Example project to run/test the bug