Ticket #122: meta5.diff

File meta5.diff, 8.1 KB (added by mmarshall, 12 years ago)

Added support for relationship fields not needing to be assigned to an attribute.

  • django/core/meta.py

     
    393393
    394394class ModelBase(type):
    395395    "Metaclass for all models"
     396   
     397    # We need to keep track of Fields which are initiated inside of the class body, but
     398    # not assined to an attribute.  (These could be ForeignKeys, ManyToManyFields, or
     399    # OneToOneFields.)
     400    _defined_fields_bank = {}
     401   
    396402    def __new__(cls, name, bases, attrs):
    397403        # If this isn't a subclass of Model, don't do anything special.
    398404        if not bases:
    399405            return type.__new__(cls, name, bases, attrs)
    400406
     407        # We must refactor the attributes around a little.  All Field class instances will be given
     408        # names (as needed) and moved to the fields list.  All attributes of the Meta class will
     409        # be moved into the main class attrs.
     410
     411        attrs["fields"] = attrs.has_key("fields") and list(attrs["fields"]) or []
     412
     413        def handle_field(obj, name):
     414            if isinstance(obj, Field):  #Check if this is a field
     415                if isinstance(obj,(ForeignKey, ManyToManyField, OneToOneField)):
     416                    obj.rel.name = name
     417                    # We need to delete this Field from the dict, as it was assigned
     418                    # to an attribute.  (We don't want to add it again later.)
     419                    del ModelBase._defined_fields_bank[id(obj)]
     420                else:
     421                    obj.set_name(name)
     422                attrs["fields"].append(obj)
     423                return True
     424            else:
     425                return False
     426
     427        # loop through the attributes, and take out the fields.
     428        for key in attrs.keys()[:]:
     429            if handle_field(attrs[key], key):
     430                del attrs[key]  # If the attr was added to fields, we want to delete it.
     431
     432        # Add all of the relationship fields that were not assigned to an attribute.
     433        attrs["fields"].extend( ModelBase._defined_fields_bank.values() )
     434        ModelBase._defined_fields_bank = {}
     435
     436        if attrs.has_key("Meta"):
     437            for name in dir(attrs["Meta"]):
     438                if name.startswith("__"): continue
     439                if name in ("fields",):
     440                    attrs[name].extend( getattr(attrs["Meta"],name) )
     441                else:
     442                    attrs[name] = getattr(attrs["Meta"],name)
     443            del attrs["Meta"]
     444
     445        # Sort the fields, so that they appear in the correct order.
     446        attrs["fields"].sort(lambda x,y: x.creation_counter - y.creation_counter)
     447
    401448        # If this model is a subclass of another Model, create an Options
    402449        # object by first copying the base class's _meta and then updating it
    403450        # with the overrides from this class.
     
    15721619    # database level.
    15731620    empty_strings_allowed = True
    15741621
    1575     def __init__(self, name, verbose_name=None, primary_key=False,
     1622    # Will be increased each time a Field object is instanced.  Used to
     1623    # retain the order of fields.
     1624    creation_counter = 0
     1625
     1626    def __init__(self, name=None, verbose_name=None, primary_key=False,
    15761627        maxlength=None, unique=False, blank=False, null=False, db_index=None,
    15771628        core=False, rel=None, default=NOT_PROVIDED, editable=True,
    15781629        prepopulate_from=None, unique_for_date=None, unique_for_month=None,
    15791630        unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
    15801631        help_text=''):
    15811632        self.name = name
    1582         self.verbose_name = verbose_name or name.replace('_', ' ')
     1633        self.original_verbose_name = verbose_name
     1634        self.verbose_name = verbose_name or name and name.replace('_', ' ')
    15831635        self.primary_key = primary_key
    15841636        self.maxlength, self.unique = maxlength, unique
    15851637        self.blank, self.null = blank, null
     
    16041656        else:
    16051657            self.db_index = db_index
    16061658
     1659        # Increase the creation counter, and save our local copy.
     1660        self.creation_counter = Field.creation_counter
     1661        Field.creation_counter += 1
     1662
     1663    def set_name(self, name ):
     1664        """
     1665        Sets the name, and generates the verbose_name from it if needed.
     1666        This function is here for when the name needs to be set later, (such as if it needs to be obtained from
     1667        a the attribute name that stores the Field instance.)
     1668        """
     1669        if not self.original_verbose_name:
     1670            # If the verbose name was originally not specified, we will assume that
     1671            # the user intends for the first argument passed to __init__ to be the verbose_name.
     1672            self.verbose_name = self.name
     1673           
     1674        self.name = name
     1675        self.verbose_name = self.verbose_name or name and name.replace('_', ' ')
     1676           
    16071677    def pre_save(self, obj, value, add):
    16081678        """
    16091679        Hook for altering the object obj based on the value of this field and
     
    17891859
    17901860class DateField(Field):
    17911861    empty_strings_allowed = False
    1792     def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
     1862    def __init__(self, name=None, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
    17931863        self.auto_now, self.auto_now_add = auto_now, auto_now_add
    17941864        if auto_now or auto_now_add:
    17951865            kwargs['editable'] = False
     
    18451915        return [formfields.EmailField]
    18461916
    18471917class FileField(Field):
    1848     def __init__(self, name, verbose_name=None, upload_to='', **kwargs):
     1918    def __init__(self, name=None, verbose_name=None, upload_to='', **kwargs):
    18491919        self.upload_to = upload_to
    18501920        Field.__init__(self, name, verbose_name, **kwargs)
    18511921
     
    19101980
    19111981class FloatField(Field):
    19121982    empty_strings_allowed = False
    1913     def __init__(self, name, verbose_name=None, max_digits=None, decimal_places=None, **kwargs):
     1983    def __init__(self, name=None, verbose_name=None, max_digits=None, decimal_places=None, **kwargs):
    19141984        self.max_digits, self.decimal_places = max_digits, decimal_places
    19151985        Field.__init__(self, name, verbose_name, **kwargs)
    19161986
     
    19922062
    19932063class TimeField(Field):
    19942064    empty_strings_allowed = False
    1995     def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
     2065    def __init__(self, name=None, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
    19962066        self.auto_now, self.auto_now_add  = auto_now, auto_now_add
    19972067        if auto_now or auto_now_add:
    19982068            kwargs['editable'] = False
     
    20192089        return [formfields.TimeField]
    20202090
    20212091class URLField(Field):
    2022     def __init__(self, name, verbose_name=None, verify_exists=True, **kwargs):
     2092    def __init__(self, name=None, verbose_name=None, verify_exists=True, **kwargs):
    20232093        if verify_exists:
    20242094            kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
    20252095        Field.__init__(self, name, verbose_name, **kwargs)
     
    20322102        return [formfields.USStateField]
    20332103
    20342104class XMLField(Field):
    2035     def __init__(self, name, verbose_name=None, schema_path=None, **kwargs):
     2105    def __init__(self, name=None, verbose_name=None, schema_path=None, **kwargs):
    20362106        self.schema_path = schema_path
    20372107        Field.__init__(self, name, verbose_name, **kwargs)
    20382108
     
    20652135            lookup_overrides=kwargs.pop('lookup_overrides', None),
    20662136            raw_id_admin=kwargs.pop('raw_id_admin', False))
    20672137        Field.__init__(self, **kwargs)
     2138        ModelBase._defined_fields_bank[id(self)]=self
    20682139
    20692140    def get_manipulator_field_objs(self):
    20702141        return [formfields.IntegerField]
     
    20802151            filter_interface=kwargs.pop('filter_interface', None),
    20812152            limit_choices_to=kwargs.pop('limit_choices_to', None))
    20822153        Field.__init__(self, **kwargs)
     2154        ModelBase._defined_fields_bank[id(self)]=self
    20832155
    20842156    def get_manipulator_field_objs(self):
    20852157        choices = self.get_choices(include_blank=False)
     
    21052177            raw_id_admin=kwargs.pop('raw_id_admin', False))
    21062178        kwargs['primary_key'] = True
    21072179        IntegerField.__init__(self, **kwargs)
     2180        ModelBase._defined_fields_bank[id(self)]=self
    21082181
    21092182####################
    21102183# RELATIONSHIPS    #
Back to Top