Ticket #122: meta3.diff

File meta3.diff, 4.7 KB (added by mmarshall, 12 years ago)

A third version of the patch. Better support for ForeignKey, ManyToManyField, and OneToOneField.

  • django/core/meta.py

     
    368368        if not bases:
    369369            return type.__new__(cls, name, bases, attrs)
    370370
     371        # We must refactor the attributes around a little.  All Field class instances will be given
     372        # names (as needed) and moved to the fields list.
     373
     374        attrs["fields"] = attrs.has_key("fields") and list(attrs["fields"]) or []
     375
     376        def handle_ForeignKey(obj):
     377            if isinstance(obj, Model):
     378                attrs["fields"].append(ForeignKey(obj))
     379            elif type(obj) in (list, tuple):
     380                if isinstance(obj[0], ModelBase) and type(obj[1]) == dict:
     381                    attrs["fields"].append(ForeignKey(obj[0], **obj[1]))
     382                else:
     383                    for i in obj: handle_ForeignKey(i)
     384            else:
     385                raise ValueError("Cannot make ForeignKey from "+str(obj))
     386
     387        def handle_field(obj, name):
     388            if isinstance(obj, Field):  #Check if this is a field
     389                if isinstance(obj,(ForeignKey, ManyToManyField, OneToOneField)):
     390                    obj.rel.name = name
     391                else:
     392                    obj.set_name(name)
     393                attrs["fields"].append(obj)
     394                return True
     395            elif name == "ForeignKey":
     396                handle_ForeignKey(obj)
     397                return True
     398            return False
     399
     400        # loop through the attributes, and take out the fields.
     401        for key in attrs.keys()[:]:
     402            if handle_field(attrs[key], key):
     403                del attrs[key]  # If the attr was added to fields, we want to delete it.
     404
     405        if attrs.has_key("Field"):
     406            for name in dir(attrs["Field"]):
     407                handle_field(getattr(attrs["Field"],name),name)
     408            del attrs["Field"]
     409
     410        if attrs.has_key("Meta"):
     411            for name in dir(attrs["Meta"]):
     412                if name.startswith("__"): continue
     413                if name in ("fields",):
     414                    attrs[name] += getattr(attrs["Meta"],name)
     415                else:
     416                    attrs[name] = getattr(attrs["Meta"],name)
     417            del attrs["Meta"]
     418
     419        # Sort the fields, so that they appear in the correct order.
     420        attrs["fields"].sort(lambda x,y: x.creation_counter - y.creation_counter)
     421
    371422        # If this model is a subclass of another Model, create an Options
    372423        # object by first copying the base class's _meta and then updating it
    373424        # with the overrides from this class.
     
    15511602    # database level.
    15521603    empty_strings_allowed = True
    15531604
    1554     def __init__(self, name, verbose_name=None, primary_key=False,
     1605    # Will be increaced each time a Field object is instanced.  Used to
     1606    # retain the order of fields.
     1607    creation_counter = 0
     1608
     1609    def __init__(self, name=None, verbose_name=None, primary_key=False,
    15551610        maxlength=None, unique=False, blank=False, null=False, db_index=None,
    15561611        core=False, rel=None, default=NOT_PROVIDED, editable=True,
    15571612        prepopulate_from=None, unique_for_date=None, unique_for_month=None,
    15581613        unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
    15591614        help_text=''):
    15601615        self.name = name
    1561         self.verbose_name = verbose_name or name.replace('_', ' ')
     1616        self.original_verbose_name = verbose_name
     1617        self.verbose_name = verbose_name or name and name.replace('_', ' ')
    15621618        self.primary_key = primary_key
    15631619        self.maxlength, self.unique = maxlength, unique
    15641620        self.blank, self.null = blank, null
     
    15831639        else:
    15841640            self.db_index = db_index
    15851641
     1642        # Increace the creation counter, and save our local copy.
     1643        self.creation_counter = Field.creation_counter
     1644        Field.creation_counter += 1
     1645
     1646    def set_name(self, name ):
     1647        """
     1648        Sets the name, and generates the verbose_name from it if needed.
     1649        This function is here for when the name needs to be set later, (such as if it needs to be obtained from
     1650        a the attribute name that stores the Field instance.)
     1651        """
     1652        if not self.original_verbose_name:
     1653            # If the verbose name was originally not specified, we will assume that
     1654            # the user intends for the first argument passed to __init__ to be the verbose_name.
     1655            self.verbose_name = self.name
     1656           
     1657        self.name = name
     1658        self.verbose_name = self.verbose_name or name and name.replace('_', ' ')
     1659           
    15861660    def pre_save(self, obj, value, add):
    15871661        """
    15881662        Hook for altering the object obj based on the value of this field and
Back to Top