Ticket #8309: genericforeignkey_fail_in_abstract_models_r8507.diff

File genericforeignkey_fail_in_abstract_models_r8507.diff, 4.9 KB (added by Manuel Saelices, 16 years ago)

Patch that fixes problem (with tests)

  • django/db/models/base.py

     
    9595                # Things without _meta aren't functional models, so they're
    9696                # uninteresting parents.
    9797                continue
     98            field_names = set([f.name for f in new_class._meta.local_fields + \
     99                    new_class._meta.virtual_fields + \
     100                    new_class._meta.many_to_many ])
    98101            if not base._meta.abstract:
    99102                if base in o2o_map:
    100103                    field = o2o_map[base]
     
    108111                new_class._meta.parents[base] = field
    109112            else:
    110113                # The abstract base class case.
    111                 names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many])
    112                 for field in base._meta.local_fields + base._meta.local_many_to_many:
    113                     if field.name in names:
     114                parent_fields = base._meta.local_fields + \
     115                                base._meta.local_many_to_many
     116                for field in parent_fields:
     117                    if field.name in field_names:
    114118                        raise FieldError('Local field %r in class %r clashes with field of similar name from abstract base class %r'
    115119                                % (field.name, name, base.__name__))
    116120                    new_class.add_to_class(field.name, copy.deepcopy(field))
    117 
     121            # checking for virtual fields, like GenericForeignKey (see #8309)
     122            for field in base._meta.virtual_fields:
     123                if base._meta.abstract and field.name in field_names:
     124                    raise FieldError('Local field %r in class %r clashes with field of similar name from abstract base class %r'
     125                            % (field.name, name, base.__name__))
     126                new_class.add_to_class(field.name, copy.deepcopy(field))
    118127        if abstract:
    119128            # Abstract base models can't be instantiated and don't appear in
    120129            # the list of models for an app. We do the final setup for them a
  • django/db/models/options.py

     
    2626class Options(object):
    2727    def __init__(self, meta, app_label=None):
    2828        self.local_fields, self.local_many_to_many = [], []
     29        self.virtual_fields = []
    2930        self.module_name, self.verbose_name = None, None
    3031        self.verbose_name_plural = None
    3132        self.db_table = ''
     
    152153        if hasattr(self, '_name_map'):
    153154            del self._name_map
    154155
     156    def add_virtual_field(self, field):
     157        self.virtual_fields.append(field)
     158
    155159    def setup_pk(self, field):
    156160        if not self.pk and field.primary_key:
    157161            self.pk = field
  • django/contrib/contenttypes/generic.py

     
    2828    def contribute_to_class(self, cls, name):
    2929        # Make sure the fields exist (these raise FieldDoesNotExist,
    3030        # which is a fine error to raise here)
     31        cls._meta.add_virtual_field(self)
    3132        self.name = name
     33        self.attname = name
    3234        self.model = cls
    3335        self.cache_attr = "_%s_cache" % name
    3436
  • tests/modeltests/generic_relations/models.py

     
    7575    def __unicode__(self):
    7676        return self.name
    7777
     78class ValuableTaggedItem(TaggedItem):
     79    value = models.PositiveSmallIntegerField()
     80
     81
    7882__test__ = {'API_TESTS':"""
    7983# Create the world in 7 lines of code...
    8084>>> lion = Animal(common_name="Lion", latin_name="Panthera leo")
     
    211215<p><label for="id_generic_relations-taggeditem-content_type-object_id-1-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-1-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-1-tag" maxlength="50" /></p>
    212216<p><label for="id_generic_relations-taggeditem-content_type-object_id-1-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-1-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-1-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-1-id" id="id_generic_relations-taggeditem-content_type-object_id-1-id" /></p>
    213217
     218# GenericForeignKey should work with abstract classes (see #8309) #############
     219
     220>>> valuedtag = ValuableTaggedItem(content_object=quartz, tag="shiny", value=10)
     221
    214222"""}
Back to Top