Made it explicit if you accidentally override a Field from a parent model.

This was always not working reliably (model initialization and serialization
were two of the problems). Now, it's an explicit error. Also, documented.

Fixed #10252.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9974 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2009-03-04 10:39:29 +00:00
parent f9c8eeb311
commit 7197a4dcb7
2 changed files with 41 additions and 10 deletions

View File

@ -94,6 +94,16 @@ class ModelBase(type):
new_class._meta.virtual_fields
field_names = set([f.name for f in new_fields])
parent_fields = base._meta.local_fields + base._meta.local_many_to_many
# Check for clashes between locally declared fields and those
# on the base classes (we cannot handle shadowed fields at the
# moment).
for field in parent_fields:
if field.name in field_names:
raise FieldError('Local field %r in class %r clashes '
'with field of similar name from '
'base class %r' %
(field.name, name, base.__name__))
if not base._meta.abstract:
# Concrete classes...
if base in o2o_map:
@ -107,16 +117,7 @@ class ModelBase(type):
else:
# .. and abstract ones.
# Check for clashes between locally declared fields and those
# on the ABC.
parent_fields = base._meta.local_fields + base._meta.local_many_to_many
for field in parent_fields:
if field.name in field_names:
raise FieldError('Local field %r in class %r clashes '\
'with field of similar name from '\
'abstract base class %r' % \
(field.name, name, base.__name__))
new_class.add_to_class(field.name, copy.deepcopy(field))
# Pass any non-abstract parent classes onto child.
@ -131,7 +132,8 @@ class ModelBase(type):
new_manager = manager._copy_to_model(new_class)
new_class.add_to_class(mgr_name, new_manager)
# Inherit virtual fields (like GenericForeignKey) from the parent class
# Inherit virtual fields (like GenericForeignKey) from the parent
# class
for field in base._meta.virtual_fields:
if base._meta.abstract and field.name in field_names:
raise FieldError('Local field %r in class %r clashes '\

View File

@ -1006,3 +1006,32 @@ field or method to every class that inherits the mix-in. Try to keep your
inheritance hierarchies as simple and straightforward as possible so that you
won't have to struggle to work out where a particular piece of information is
coming from.
Field name "hiding" is not permitted
-------------------------------------
In normal Python class inheritance, it is permissible for a child class to
override any attribute from the parent class. In Django, this is not permitted
for attributes that are :class:`~django.db.models.fields.Field` instances (at
least, not at the moment). If a base class has a field called ``author``, you
cannot create another model field called ``author`` in any class that inherits
from that base class.
Overriding fields in a parent model leads to difficulties in areas such as
initialising new instances (specifying which field is being intialised in
``Model.__init__``) and serialization. These are features which normal Python
class inheritance doesn't have to deal with in quite the same way, so the
difference between Django model inheritance and Python class inheritance isn't
merely arbitrary.
This restriction only applies to attributes which are
:class:`~django.db.models.fields.Field` instances. Normal Python attributes
can be overridden if you wish. It also only applies to the name of the
attribute as Python sees it: if you are manually specifying the database
column name, you can have the same column name appearing in both a child and
an ancestor model for multi-table inheritance (they are columns in two
different database tables).
Django will raise a ``FieldError`` exception if you override any model field
in any ancestor model.