Django

Code

Changeset 8855

Show
Ignore:
Timestamp:
09/02/08 10:26:00 (3 months ago)
Author:
jacob
Message:

Fixed #8309: subclasses now inherit GenericForeignKey correctly. There's also now an internal API so that other "virtual fields" like GFK can be inherited as well. Thanks, msaelices.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/contrib/contenttypes/generic.py

    r8644 r8855  
    2525 
    2626    def contribute_to_class(self, cls, name): 
    27         # Make sure the fields exist (these raise FieldDoesNotExist, 
    28         # which is a fine error to raise here) 
    2927        self.name = name 
    3028        self.model = cls 
    3129        self.cache_attr = "_%s_cache" % name 
     30        cls._meta.add_virtual_field(self) 
    3231 
    3332        # For some reason I don't totally understand, using weakrefs here doesn't work. 
  • django/trunk/django/db/models/base.py

    r8851 r8855  
    8888                # uninteresting parents. 
    8989                continue 
     90                 
     91            # All the fields of any type declared on this model 
     92            new_fields = new_class._meta.local_fields + \ 
     93                         new_class._meta.many_to_many + \ 
     94                         new_class._meta.virtual_fields 
     95            field_names = set([f.name for f in new_fields]) 
     96                 
     97            # Concrete classes... 
    9098            if not base._meta.abstract: 
    9199                if base in o2o_map: 
     
    99107                    new_class.add_to_class(attr_name, field) 
    100108                new_class._meta.parents[base] = field 
    101             else: 
    102                 # The abstract base class case. 
    103                 names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) 
    104                 for field in base._meta.local_fields + base._meta.local_many_to_many: 
    105                     if field.name in names: 
    106                         raise FieldError('Local field %r in class %r clashes with field of similar name from abstract base class %r' 
    107                                 % (field.name, name, base.__name__)) 
     109             
     110            # .. and abstract ones. 
     111            else: 
     112                # Check for clashes between locally declared fields and those on the ABC. 
     113                parent_fields = base._meta.local_fields + base._meta.local_many_to_many 
     114                for field in parent_fields: 
     115                    if field.name in field_names: 
     116                        raise FieldError('Local field %r in class %r clashes '\ 
     117                                         'with field of similar name from '\ 
     118                                         'abstract base class %r' % \ 
     119                                            (field.name, name, base.__name__)) 
    108120                    new_class.add_to_class(field.name, copy.deepcopy(field)) 
    109121 
     
    116128                    new_manager = manager._copy_to_model(new_class) 
    117129                    new_class.add_to_class(mgr_name, new_manager) 
     130         
     131            # Inherit virtual fields (like GenericForeignKey) from the parent class 
     132            for field in base._meta.virtual_fields: 
     133                if base._meta.abstract and field.name in field_names: 
     134                    raise FieldError('Local field %r in class %r clashes '\ 
     135                                     'with field of similar name from '\ 
     136                                     'abstract base class %r' % \ 
     137                                        (field.name, name, base.__name__)) 
     138                new_class.add_to_class(field.name, copy.deepcopy(field)) 
     139         
    118140        if abstract: 
    119141            # Abstract base models can't be instantiated and don't appear in 
  • django/trunk/django/db/models/options.py

    r8851 r8855  
    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 
     
    156157            del self._name_map 
    157158 
     159    def add_virtual_field(self, field): 
     160        self.virtual_fields.append(field) 
     161 
    158162    def setup_pk(self, field): 
    159163        if not self.pk and field.primary_key: 
  • django/trunk/tests/modeltests/generic_relations/models.py

    r8815 r8855  
    2727    def __unicode__(self): 
    2828        return self.tag 
     29 
     30class ValuableTaggedItem(TaggedItem): 
     31    value = models.PositiveIntegerField() 
    2932 
    3033class Comparison(models.Model): 
     
    205208[<Comparison: tiger is stronger than None>] 
    206209 
     210# GenericForeignKey should work with subclasses (see #8309) 
     211>>> quartz = Mineral.objects.create(name="Quartz", hardness=7) 
     212>>> valuedtag = ValuableTaggedItem(content_object=quartz, tag="shiny", value=10) 
     213>>> valuedtag.save() 
     214>>> valuedtag.content_object 
     215<Mineral: Quartz> 
    207216 
    208217# GenericInlineFormSet tests ##################################################