Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#24936 closed Bug (needsinfo)

AttributeError appears when one tries to use defer/only for a field in a model that has the reverse relationship explicitly removed

Reported by: lukawoj Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

While investigating #24612 I discovered that if one tries to use defer/only for a field in a model that has the reverse relationship explicitly removed, AttributeError appears. Code changed since #24612 was logged and now it throws following error:

AttributeError: 'ManyToOneRel' object has no attribute 'attname'

Models:

# models.py
from django.db import models
from django.contrib.auth.models import User

class Message(models.Model):
        content = models.CharField(max_length=10)

class MessageParticipant(models.Model):
        msg = models.ForeignKey(Message, related_name='participants')
        user = models.ForeignKey(User, related_name='+')

Query to use:

list(Message.objects.all().only('participants__user__username'))

Error:

Traceback (most recent call last):
  File "C:/dev/django_con/django_sprint_2015/django_sprint/django/tests\defer\tests.py", line 279, in test_defer_only
    list(Message.objects.all().only('participants__user__username'))
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\query.py", line 258, in __iter__
    self._fetch_all()
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\query.py", line 1063, in _fetch_all
    self._result_cache = list(self.iterator())
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\query.py", line 52, in __iter__
    results = compiler.execute_sql()
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\compiler.py", line 835, in execute_sql
    sql, params = self.as_sql()
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\compiler.py", line 384, in as_sql
    extra_select, order_by, group_by = self.pre_sql_setup()
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\compiler.py", line 48, in pre_sql_setup
    self.setup_query()
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\compiler.py", line 39, in setup_query
    self.select, self.klass_info, self.annotation_col_map = self.get_select()
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\compiler.py", line 196, in get_select
    for c in self.get_default_columns():
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\compiler.py", line 504, in get_default_columns
    only_load = self.deferred_to_columns()
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\compiler.py", line 772, in deferred_to_columns
    self.query.deferred_to_data(columns, self.query.get_loaded_field_names_cb)
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\query.py", line 684, in deferred_to_data
    callback(target, model, values)
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\query.py", line 1804, in get_loaded_field_names_cb
    target[model] = {f.attname for f in fields}
  File "C:\dev\django_con\django_sprint_2015\django_sprint\django\django\db\models\sql\query.py", line 1804, in <setcomp>
    target[model] = {f.attname for f in fields}
AttributeError: 'ManyToOneRel' object has no attribute 'attname'

Change History (1)

comment:1 Changed 5 years ago by Simon Charette

Resolution: needsinfo
Status: newclosed

Is only() even supposed to work with ManyToOneRel?

What are you expecting Message.objects.only('participants__user__username') to return since m2m relationships are not implicitly prefetched?

What does the following yields?

Message.objects.prefetch_related(
    Prefetch('participants', queryset=MessageParticipant.objects.only('user__username')),
)
Version 0, edited 5 years ago by Simon Charette (next)
Note: See TracTickets for help on using tickets.
Back to Top