mirror of
https://github.com/django/django.git
synced 2025-05-30 02:36:29 +00:00
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:
parent
f9c8eeb311
commit
7197a4dcb7
@ -94,6 +94,16 @@ class ModelBase(type):
|
|||||||
new_class._meta.virtual_fields
|
new_class._meta.virtual_fields
|
||||||
field_names = set([f.name for f in new_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:
|
if not base._meta.abstract:
|
||||||
# Concrete classes...
|
# Concrete classes...
|
||||||
if base in o2o_map:
|
if base in o2o_map:
|
||||||
@ -107,16 +117,7 @@ class ModelBase(type):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
# .. and abstract ones.
|
# .. 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:
|
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))
|
new_class.add_to_class(field.name, copy.deepcopy(field))
|
||||||
|
|
||||||
# Pass any non-abstract parent classes onto child.
|
# Pass any non-abstract parent classes onto child.
|
||||||
@ -131,7 +132,8 @@ class ModelBase(type):
|
|||||||
new_manager = manager._copy_to_model(new_class)
|
new_manager = manager._copy_to_model(new_class)
|
||||||
new_class.add_to_class(mgr_name, new_manager)
|
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:
|
for field in base._meta.virtual_fields:
|
||||||
if base._meta.abstract and field.name in field_names:
|
if base._meta.abstract and field.name in field_names:
|
||||||
raise FieldError('Local field %r in class %r clashes '\
|
raise FieldError('Local field %r in class %r clashes '\
|
||||||
|
@ -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
|
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
|
won't have to struggle to work out where a particular piece of information is
|
||||||
coming from.
|
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.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user