Opened 11 years ago
Closed 11 years ago
#22850 closed Uncategorized (invalid)
False reverse accessor clash with inherited classes
| Reported by: | Ilya Semenov | Owned by: | nobody | 
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.4 | 
| 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
Consider the following models.py:
class Base(models.Model): field1 = models.IntegerField() class Derived(Base): field2 = models.IntegerField() class Pointer(models.Model): base = models.ForeignKey(Base) derived = models.ForeignKey(Derived)
it crashes:
Unhandled exception in thread started by <function wrapper at 0x105daab90>
Traceback (most recent call last):
  File "/Users/semenov/work/project/venv/src/django/django/utils/autoreload.py", line 170, in wrapper
    fn(*args, **kwargs)
  File "/Users/semenov/work/project/venv/src/django/django/core/management/commands/runserver.py", line 104, in inner_run
    self.validate(display_num_errors=True)
  File "/Users/semenov/work/project/venv/src/django/django/core/management/base.py", line 361, in validate
    return self.check(app_configs=app_configs, display_num_errors=display_num_errors)
  File "/Users/semenov/work/project/venv/src/django/django/core/management/base.py", line 413, in check
    raise CommandError(msg)
django.core.management.base.CommandError: System check identified some issues:
ERRORS:
project.Pointer.derived: (fields.E304) Reverse accessor for 'Pointer.derived' clashes with reverse accessor for 'Pointer.base'.
	HINT: Add or change a related_name argument to the definition for 'Pointer.derived' or 'Pointer.base'.
However, if I rewrite it to the semantically equivalent form:
class AbstractBase(models.Model): field1 = models.IntegerField() class Meta: abstract = True class Base(AbstractBase): pass class Derived(AbstractBase): field2 = models.IntegerField() class Pointer(models.Model): base = models.ForeignKey(Base) derived = models.ForeignKey(Derived)
it works fine.
EXPECTED RESULT: both cases should work identically (create identical database tables and ORM accessors).
Change History (3)
comment:1 by , 11 years ago
comment:2 by , 11 years ago
| Version: | 1.7-beta-2 → 1.4 | 
|---|
I tested both cases on Django 1.4.X branch, the first version crashed with similar error:
Unhandled exception in thread started by <bound method Command.inner_run of <django.core.management.commands.runserver.Command object at 0x101e3b110>>
Traceback (most recent call last):
  File "/Users/semenov/work/project/venv/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 91, in inner_run
    self.validate(display_num_errors=True)
  File "/Users/semenov/work/project/venv/lib/python2.7/site-packages/django/core/management/base.py", line 270, in validate
    raise CommandError("One or more models did not validate:\n%s" % error_text)
django.core.management.base.CommandError: One or more models did not validate:
project.pointer: Accessor for field 'derived' clashes with related field 'Derived.pointer_set'. Add a related_name argument to the definition for 'derived'.
The second version worked fine.
comment:3 by , 11 years ago
| Resolution: | → invalid | 
|---|---|
| Status: | new → closed | 
The two forms are really not equivalent -- they will created different database tables. An explanation of the differences is here.
Having a ForeignKey to both Base and Derived in the first example in really redundant as they will refer to the same database column (Base.id). I believe that's the reason for the validation error.
Did the first version work in older versions of Django?