Opened 4 years ago

Closed 4 years ago

#22466 closed Bug (fixed)

'ManyToOneRel' object has no attribute 'rel'

Reported by: Takis Issaris Owned by: Anssi Kääriäinen
Component: Database layer (models, ORM) Version: 1.7-beta-2
Severity: Release blocker Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Simon Charette)

I just installed Django 1.7b1 in my development virtualenv where I normally use Django 1.6.1. After fixing several expected things (mimetype, ugettext), I got an error which I could not find a reference to in the release notes:
AttributeError at /orders/price/ 'ManyToOneRel' object has no attribute 'rel'

Request Method: POST
Request URL: http://192.168.3.200:8001/orders/price/
Django Version: 1.7b1
Python Executable: /home/ic/adk/dj/bin/python
Python Version: 2.7.3

Python Path: ['/home/ic/adk/dj/adkwoningdev', '/home/ic/adk/dj/lib/python2.7/site-packages/adkw_calctable-0.1-py2.7.egg', '/home/ic/adk/dj/lib/python2.7/site-packages/adkw_portsectionheights-0.1-py2.7.egg', '/home/ic/adk/dj/lib/python27.zip', '/home/ic/adk/dj/lib/python2.7', '/home/ic/adk/dj/lib/python2.7/plat-linux2', '/home/ic/adk/dj/lib/python2.7/lib-tk', '/home/ic/adk/dj/lib/python2.7/lib-old', '/home/ic/adk/dj/lib/python2.7/lib-dynload', '/opt/python-2.7.3/lib/python2.7', '/opt/python-2.7.3/lib/python2.7/plat-linux2', '/opt/python-2.7.3/lib/python2.7/lib-tk', '/home/ic/adk/dj/lib/python2.7/site-packages', '/home/ic/adk/dj/lib/python2.7/site-packages/PIL']

Server time: Thu, 17 Apr 2014 12:10:24 +0200

Installed Applications: ('django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.admin', 'django.contrib.admindocs', 'south', 'orders', 'siunits', 'portsections', 'springcalc', 'ral', 'printer', 'springorders', 'glassorders', 'suppliers', 'scanner', 'statistics', 'django_extensions', 'panels', 'tracks', 'drive', 'person', 'discounts', 'production', 'productionplanning', 'nonstdports', 'unstructuredorders', 'adkapp5', 'loading', 'paints', 'deliverynote', 'mail', 'download', 'experiments')

Installed Middleware: ('django.middleware.gzip.GZipMiddleware', 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'mymid.CustomMiddleware')

Traceback: File "/home/ic/adk/dj/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 113. response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/ic/adk/dj/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view 22. return view_func(request, *args, **kwargs) File "/home/ic/adk/dj/adkwoningdev/orders/views.py" in price 161. price = order.get_price_estimate() File "/home/ic/adk/dj/adkwoningdev/orders/models.py" in get_price_estimate 1473. return self.count * self.process_order_items(self.price_item_discount) File "/home/ic/adk/dj/adkwoningdev/orders/models.py" in process_order_items 1198. price, panel = self.calculate_panelprice() File "/home/ic/adk/dj/adkwoningdev/orders/models.py" in calculate_panelprice 1570. if len(panels) > 0: File "/home/ic/adk/dj/lib/python2.7/site-packages/django/db/models/query.py" in __len__ 122. self._fetch_all() File "/home/ic/adk/dj/lib/python2.7/site-packages/django/db/models/query.py" in _fetch_all 961. self._result_cache = list(self.iterator()) File "/home/ic/adk/dj/lib/python2.7/site-packages/django/db/models/query.py" in iterator 265. for row in compiler.results_iter(): File "/home/ic/adk/dj/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in results_iter 694. for rows in self.execute_sql(MULTI): File "/home/ic/adk/dj/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql 769. sql, params = self.as_sql() File "/home/ic/adk/dj/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in as_sql 100. ordering, o_params, ordering_group_by = self.get_ordering() File "/home/ic/adk/dj/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in get_ordering 424. self.query.get_meta(), default_order=asc): File "/home/ic/adk/dj/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in find_ordering_name 464. if field.rel and path and opts.ordering: Exception Type: AttributeError at /orders/price/ Exception Value: 'ManyToOneRel' object has no attribute 'rel'

Attachments (1)

test22466.diff (612 bytes) - added by Tim Graham 4 years ago.

Download all attachments as: .zip

Change History (14)

comment:1 Changed 4 years ago by Baptiste Mispelon

Resolution: needsinfo
Status: newclosed

Hi,

Could you show your model definitions and the code you're using to trigger this error (if you could reduce this error to a short snippet of code, that would also really help in reproducing it)?

Thanks!

comment:2 Changed 4 years ago by Takis Issaris

Hi,

The codebase is large, so I will try to extract the smallest possible amount of code which still triggers the error. I cannot do it right away though, but I'll try to have a go after work this evening or tomorrow evening.

comment:3 Changed 4 years ago by Takis Issaris

Hi,

I finally found the time to minimize the application code, and track down the problem.

from django.db import models

class Article(models.Model):
    code = models.CharField(max_length=64, unique=True)
    description = models.CharField(max_length=256, blank=True)

class Price(models.Model):
    article = models.ForeignKey('Article', null=True)
    price = models.DecimalField(max_digits=8, decimal_places=2)
import logging
from django.http import HttpResponse
from orders.models import Article

def testbug(request):
    objs = Article.objects.all().order_by('price')
    logging.debug("len articles: %d", len(objs))
    return HttpResponse("")
from django.conf.urls import patterns, url
urlpatterns = patterns('',
    url(r'^orders/', 'orders.views.testbug'),
)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
SECRET_KEY = 'xyz'
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'orders',
)
MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'adkw.urls'
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
STATIC_URL = '/static/'
Environment:


Request Method: GET
Request URL: http://localhost:8001/orders/

Django Version: 1.7b3
Python Version: 2.7.6
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'orders')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware')


Traceback:
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  113.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/ic/test/bug2/adkw/orders/views.py" in testbug
  7.     logging.debug("len articles: %d", len(objs))
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/db/models/query.py" in __len__
  122.         self._fetch_all()
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/db/models/query.py" in _fetch_all
  961.             self._result_cache = list(self.iterator())
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/db/models/query.py" in iterator
  265.         for row in compiler.results_iter():
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in results_iter
  698.         for rows in self.execute_sql(MULTI):
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
  773.             sql, params = self.as_sql()
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in as_sql
  101.         ordering, o_params, ordering_group_by = self.get_ordering()
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in get_ordering
  428.                         self.query.get_meta(), default_order=asc):
File "/home/ic/test/bug2/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in find_ordering_name
  468.         if field.rel and path and opts.ordering:

Exception Type: AttributeError at /orders/
Exception Value: 'ManyToOneRel' object has no attribute 'rel'

In the view I'm ordering by the "price" field *which is not* in the Article class. For some reason this triggered no errors with Django 1.6 and earlier, only 1.7 complains.

Removing the 'orders' app from the INSTALLED_APPS list, gets rid of the error. I figured because it wasn't being used, but it appears Django 1.7 finds the apps anyway?

comment:4 Changed 4 years ago by Takis Issaris

Version: 1.7-beta-11.7-beta-2

comment:5 Changed 4 years ago by Shai Berger

I think you're getting an ordering on the reverse relation (that is, with the reduced app, ordering Article instances by the id's of related Price instances). You probably intended order_by('price__price') (if that works, and the original doesn't, this should probably be a release-blocker bug).

comment:6 Changed 4 years ago by Takis Issaris

I can confirm that replacing order_by('price') by order_by('price_ _price') as you stated, makes the exception disappear. I'm having a closer look at what's happening.

comment:7 Changed 4 years ago by Takis Issaris

I just compared the behaviors:

Django 1.6.4

objs = Article.objects.all()
SELECT "orders_article"."id", "orders_article"."code", "orders_article"."description"
FROM "orders_article" 
pk 1 code A price 2
pk 2 code B price 1

objs = Article.objects.all().order_by('price')
SELECT "orders_article"."id", "orders_article"."code", "orders_article"."description" 
FROM "orders_article"
LEFT OUTER JOIN "orders_price" ON ( "orders_article"."id" = "orders_price"."article_id" )
ORDER BY "orders_price"."id" ASC 
pk 1 code A price 2
pk 2 code B price 1

objs = Article.objects.all().order_by('price_ _price'):
SELECT "orders_article"."id", "orders_article"."code", "orders_article"."description"
FROM "orders_article"
LEFT OUTER JOIN "orders_price" ON ( "orders_article"."id" = "orders_price"."article_id" )
ORDER BY "orders_price"."price" ASC 
pk 2 code B price 1
pk 1 code A price 2

Django 1.7b3

objs = Article.objects.all()
SELECT "orders_article"."id", "orders_article"."code", "orders_article"."description"
FROM "orders_article" 
pk 1 code A price 2
pk 2 code B price 1

objs = Article.objects.all().order_by('price'):
'ManyToOneRel' object has no attribute 'rel'

objs = Article.objects.all().order_by('price_ _price'):
SELECT "orders_article"."id", "orders_article"."code", "orders_article"."description"
FROM "orders_article"
LEFT OUTER JOIN "orders_price" ON ( "orders_article"."id" = "orders_price"."article_id" )
ORDER BY "orders_price"."price" ASC 
pk 2 code B price 1
pk 1 code A price 2

comment:8 Changed 4 years ago by Tim Graham

Component: UncategorizedDatabase layer (models, ORM)
Resolution: needsinfo
Severity: NormalRelease blocker
Status: closednew
Triage Stage: UnreviewedAccepted

Bisected to 20bab2cf9d02a5c6477d8aac066a635986e0d3f3. Attaching a regression test.

Changed 4 years ago by Tim Graham

Attachment: test22466.diff added

comment:9 Changed 4 years ago by Simon Charette

Description: modified (diff)

I guess a simple getattr(field, 'rel', None) should fix this?

comment:10 in reply to:  9 Changed 4 years ago by Shai Berger

Replying to charettes:

I guess a simple getattr(field, 'rel', None) should fix this?

No, we need to fix it so that the field does have a rel attribute. This is exactly like #19195, from the other side of the relation.

comment:11 Changed 4 years ago by loic84

How does ordering by the reverse of a FK even work considering there are potentially many result?

comment:12 Changed 4 years ago by Anssi Kääriäinen

Owner: changed from nobody to Anssi Kääriäinen
Status: newassigned

Ordering by reverse FK is something that is possible even if it usually doesn't make any sense. The interpretation is that one gets duplicate results.

I'll assign this to myself.

comment:13 Changed 4 years ago by Anssi Kääriäinen <akaariai@…>

Resolution: fixed
Status: assignedclosed

In 76979a257d289b99998c463023308c888662d874:

[1.7.x] Fixed #22466 -- ordering by reverse foreign key

Ordering by reverse foreign key was broken by custom lookups patch
(commit 20bab2cf9d02a5c6477d8aac066a635986e0d3f3).

Thanks to everybody who helped solving this issue. Special thanks to
Trac alias takis for reporting this.

Backport of 3b7c66a3ac from master

Note: See TracTickets for help on using tickets.
Back to Top