Index: django/db/models/base.py =================================================================== --- django/db/models/base.py (revisión: 8507) +++ django/db/models/base.py (copia de trabajo) @@ -95,6 +95,9 @@ # Things without _meta aren't functional models, so they're # uninteresting parents. continue + field_names = set([f.name for f in new_class._meta.local_fields + \ + new_class._meta.virtual_fields + \ + new_class._meta.many_to_many ]) if not base._meta.abstract: if base in o2o_map: field = o2o_map[base] @@ -108,13 +111,19 @@ new_class._meta.parents[base] = field else: # The abstract base class case. - names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) - for field in base._meta.local_fields + base._meta.local_many_to_many: - if field.name in names: + 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)) - + # checking for virtual fields, like GenericForeignKey (see #8309) + 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 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)) if abstract: # Abstract base models can't be instantiated and don't appear in # the list of models for an app. We do the final setup for them a Index: django/db/models/options.py =================================================================== --- django/db/models/options.py (revisión: 8507) +++ django/db/models/options.py (copia de trabajo) @@ -26,6 +26,7 @@ class Options(object): def __init__(self, meta, app_label=None): self.local_fields, self.local_many_to_many = [], [] + self.virtual_fields = [] self.module_name, self.verbose_name = None, None self.verbose_name_plural = None self.db_table = '' @@ -152,6 +153,9 @@ if hasattr(self, '_name_map'): del self._name_map + def add_virtual_field(self, field): + self.virtual_fields.append(field) + def setup_pk(self, field): if not self.pk and field.primary_key: self.pk = field Index: django/contrib/contenttypes/generic.py =================================================================== --- django/contrib/contenttypes/generic.py (revisión: 8507) +++ django/contrib/contenttypes/generic.py (copia de trabajo) @@ -28,7 +28,9 @@ def contribute_to_class(self, cls, name): # Make sure the fields exist (these raise FieldDoesNotExist, # which is a fine error to raise here) + cls._meta.add_virtual_field(self) self.name = name + self.attname = name self.model = cls self.cache_attr = "_%s_cache" % name Index: tests/modeltests/generic_relations/models.py =================================================================== --- tests/modeltests/generic_relations/models.py (revisión: 8507) +++ tests/modeltests/generic_relations/models.py (copia de trabajo) @@ -75,6 +75,10 @@ def __unicode__(self): return self.name +class ValuableTaggedItem(TaggedItem): + value = models.PositiveSmallIntegerField() + + __test__ = {'API_TESTS':""" # Create the world in 7 lines of code... >>> lion = Animal(common_name="Lion", latin_name="Panthera leo") @@ -211,4 +215,8 @@
+# GenericForeignKey should work with abstract classes (see #8309) ############# + +>>> valuedtag = ValuableTaggedItem(content_object=quartz, tag="shiny", value=10) + """}