Django

Code

Ticket #122: meta3.diff

File meta3.diff, 4.7 kB (added by mmarshall, 3 years ago)

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

  • django/core/meta.py

    old new  
    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