Django

Code

Changeset 7142

Show
Ignore:
Timestamp:
02/21/08 22:58:28 (6 months ago)
Author:
mtredinnick
Message:

queryset-refactor: Added the ability to manually specify a child-parent link.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/queryset-refactor/django/db/models/base.py

    r7141 r7142  
    6060                    new_class._meta.get_latest_by = base_meta.get_latest_by 
    6161 
    62         # Do the appropriate setup for any model parents. 
    63         abstract_parents = [] 
    64         for base in parents: 
    65             if not hasattr(base, '_meta'): 
    66                 # Things without _meta aren't functional models, so they're 
    67                 # uninteresting parents. 
    68                 continue 
    69             if not base._meta.abstract: 
    70                 attr_name = '%s_ptr' % base._meta.module_name 
    71                 field = OneToOneField(base, name=attr_name, auto_created=True) 
    72                 new_class.add_to_class(attr_name, field) 
    73                 new_class._meta.parents[base] = field 
    74             else: 
    75                 abstract_parents.append(base) 
    76  
    7762        if getattr(new_class, '_default_manager', None) is not None: 
    7863            # We have a parent who set the default manager. We need to override 
     
    9479            new_class.add_to_class(obj_name, obj) 
    9580 
    96         for parent in abstract_parents: 
    97             names = [f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many] 
    98             for field in parent._meta.local_fields: 
    99                 if field.name in names: 
    100                     raise TypeError('Local field %r in class %r clashes with field of similar name from abstract base class %r' 
    101                             % (field.name, name, parent.__name__)) 
    102                 new_class.add_to_class(field.name, field) 
     81        # Do the appropriate setup for any model parents. 
     82        o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields 
     83                if isinstance(f, OneToOneField)]) 
     84        for base in parents: 
     85            if not hasattr(base, '_meta'): 
     86                # Things without _meta aren't functional models, so they're 
     87                # uninteresting parents. 
     88                continue 
     89            if not base._meta.abstract: 
     90                if base in o2o_map: 
     91                    field = o2o_map[base] 
     92                    field.primary_key = True 
     93                    new_class._meta.setup_pk(field) 
     94                else: 
     95                    attr_name = '%s_ptr' % base._meta.module_name 
     96                    field = OneToOneField(base, name=attr_name, 
     97                            auto_created=True, parent_link=True) 
     98                    new_class.add_to_class(attr_name, field) 
     99                new_class._meta.parents[base] = field 
     100            else: 
     101                names = [f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many] 
     102                for field in base._meta.local_fields: 
     103                    if field.name in names: 
     104                        raise TypeError('Local field %r in class %r clashes with field of similar name from abstract base class %r' 
     105                                % (field.name, name, base.__name__)) 
     106                    new_class.add_to_class(field.name, field) 
    103107 
    104108        if abstract: 
  • django/branches/queryset-refactor/django/db/models/fields/related.py

    r7126 r7142  
    462462class ManyToOneRel(object): 
    463463    def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None, 
    464         max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, 
    465         related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False): 
     464            max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, 
     465            related_name=None, limit_choices_to=None, lookup_overrides=None, 
     466            raw_id_admin=False, parent_link=False): 
    466467        try: 
    467468            to._meta 
     
    478479        self.raw_id_admin = raw_id_admin 
    479480        self.multiple = True 
     481        self.parent_link = parent_link 
    480482 
    481483    def get_related_field(self): 
     
    490492            max_num_in_admin=None, num_extra_on_change=None, edit_inline=False, 
    491493            related_name=None, limit_choices_to=None, lookup_overrides=None, 
    492             raw_id_admin=False): 
     494            raw_id_admin=False, parent_link=False): 
    493495        # NOTE: *_num_in_admin and num_extra_on_change are intentionally 
    494496        # ignored here. We accept them as parameters only to match the calling 
     
    497499                edit_inline=edit_inline, related_name=related_name, 
    498500                limit_choices_to=limit_choices_to, 
    499                 lookup_overrides=lookup_overrides, raw_id_admin=raw_id_admin) 
     501                lookup_overrides=lookup_overrides, raw_id_admin=raw_id_admin, 
     502                parent_link=parent_link) 
    500503        self.multiple = False 
    501504 
     
    542545            limit_choices_to=kwargs.pop('limit_choices_to', None), 
    543546            lookup_overrides=kwargs.pop('lookup_overrides', None), 
    544             raw_id_admin=kwargs.pop('raw_id_admin', False)) 
     547            raw_id_admin=kwargs.pop('raw_id_admin', False), 
     548            parent_link=kwargs.pop('parent_link', False)) 
    545549        Field.__init__(self, **kwargs) 
    546550 
  • django/branches/queryset-refactor/django/db/models/options.py

    r7141 r7142  
    114114        if field.rel and isinstance(field.rel, ManyToManyRel): 
    115115            self.local_many_to_many.insert(bisect(self.local_many_to_many, field), field) 
     116            if hasattr(self, '_m2m_cache'): 
     117                del self._m2m_cache 
    116118        else: 
    117119            self.local_fields.insert(bisect(self.local_fields, field), field) 
    118             if not self.pk and field.primary_key: 
    119                 self.pk = field 
    120                 field.serialize = False 
    121  
    122         # All of these internal caches need to be updated the next time they 
    123         # are used. 
    124         # TODO: Do this more neatly. (Also, use less caches!) 
    125         if hasattr(self, '_field_cache'): 
    126             del self._field_cache 
    127         if hasattr(self, '_m2m_cache'): 
    128             del self._m2m_cache 
     120            self.setup_pk(field) 
     121            if hasattr(self, '_field_cache'): 
     122                del self._field_cache 
     123 
    129124        if hasattr(self, '_name_map'): 
    130125            del self._name_map 
     126 
     127    def setup_pk(self, field): 
     128        if not self.pk and field.primary_key: 
     129            self.pk = field 
     130            field.serialize = False 
    131131 
    132132    def __repr__(self): 
     
    316316        for parent in self.parents: 
    317317            for obj, model in parent._meta.get_all_related_objects_with_model(): 
    318                 if obj.field.creation_counter < 0 and obj.model not in parent_list: 
     318                if (obj.field.creation_counter < 0 or obj.field.rel.parent_link) and obj.model not in parent_list: 
    319319                    continue 
    320320                if not model: 
  • django/branches/queryset-refactor/docs/model-api.txt

    r7141 r7142  
    10011001models can be made by using a string containing the model name. 
    10021002 
     1003Finally, ``OneToOneField`` takes the following extra option: 
     1004 
     1005    =======================  ============================================================ 
     1006    Argument                 Description 
     1007    =======================  ============================================================ 
     1008    ``parent_link``          When ``True`` and used in a model inherited from 
     1009                             another model, indicates that this field should 
     1010                             be used as the link from the child back to the 
     1011                             parent. See `Model inheritance`_ for more 
     1012                             details. 
     1013 
     1014                             **New in Django development version** 
     1015 
     1016    =======================  ============================================================ 
     1017 
    10031018**New in Django development version:** ``OneToOneField`` classes used to 
    10041019automatically become the primary key on a model. This is no longer true, 
     
    10361051Here's a list of all possible ``Meta`` options. No options are required. Adding 
    10371052``class Meta`` to a model is completely optional. 
     1053 
     1054``abstract`` 
     1055------------ 
     1056 
     1057**New in Django development version** 
     1058 
     1059When set to ``True``, denotes this model as an abstract base class. See 
     1060`Abstract base classes`_ for more details. Defaults to ``False``. 
    10381061 
    10391062``db_table`` 
     
    21932216you're writing your models and pay attention to the error messages. 
    21942217 
     2218Specifying the parent link field 
     2219~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     2220 
     2221As mentioned, Django will automatically create a ``OneToOneField`` linking 
     2222your child class back any non-abstract parent models. If you want to control 
     2223the name of the attribute linking back to the parent, you can create your own 
     2224link field and pass it ``parent_link=True``. For example, to explicitly 
     2225specify the field that will link ``Supplier`` to ``Place`` in the above 
     2226example, you could write:: 
     2227 
     2228    class Supplier(Place): 
     2229        parent = models.OneToOneField(Place, parent_link=True) 
     2230        ... 
     2231 
    21952232Multiple inheritance 
    21962233-------------------- 
  • django/branches/queryset-refactor/tests/modeltests/model_inheritance/models.py

    r7141 r7142  
    6868 
    6969class ParkingLot(Place): 
     70    # An explicit link to the parent (we can control the attribute name). 
     71    parent = models.OneToOneField(Place, primary_key=True, parent_link=True) 
    7072    main_site = models.ForeignKey(Place, related_name='lot') 
    7173