tickets: 122
This data as json
id | created | changetime | last_pulled_from_trac | stage | status | component | type | severity | version | resolution | summary | description | owner | reporter | keywords | easy | has_patch | needs_better_patch | needs_tests | needs_docs | ui_ux |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
122 | 2005-07-20 21:25:02 | 2007-01-17 22:12:17 | 2022-03-06 03:19:48.493110 | Unreviewed | closed | Core (Other) | enhancement | normal | fixed | [patch] Build models using fieldname=FieldClass | This is a patch to make fieldname=FieldClass type model definitions possible. It is fully backwards-compatible with the fields=(...) method. The example given in the tutorial could be re-written as such: {{{ from django.core import meta class Poll(meta.Model): question = meta.CharField(maxlength=200) pub_date = meta.DateTimeField('date published') class Choice(meta.Model): ForeignKey = Poll choice = meta.CharField(maxlength=200) votes = meta.IntegerField() }}} Other ways of defining a ForeignKey: {{{ #multiple keys can be used with tuples: ForeignKey = Poll, OtherKey #options can also be used: ForeignKey = Poll, {'edit_inline':True, 'num_in_admin':3} #the attribute name is irrelevant here: anything = ForeignKey(Poll, edit_inline=True, num_in_admin=3) }}} The implementation is quite simple. (or horribly hackish, depending on how you see things.) It simply goes through all of the attributes of the class, and adds all of the instances of 'Field' to the fields list. (after updating their names with the attribute name.) It also processes the ForeignKey field, producing ForeignKeys as needed. Provisions are in place to maintain the order of the Fields. Here is the patch: {{{ Index: django/core/meta.py =================================================================== --- django/core/meta.py (revision 253) +++ django/core/meta.py (working copy) @@ -368,6 +368,40 @@ if not bases: return type.__new__(cls, name, bases, attrs) + # We must refactor the attributes around a little. All Field class instances will be given + # names (as needed) and moved to the fields list. + + attrs["fields"] = attrs.has_key("fields") and list(attrs["fields"]) or [] + + def handle_ForeignKey(obj): + if isinstance(obj, Model): + attrs["fields"].append(ForeignKey(obj)) + elif type(obj) in (list, tuple): + if isinstance(obj[0], ModelBase) and type(obj[1]) == dict: + attrs["fields"].append(ForeignKey(obj[0], **obj[1])) + else: + for i in obj: handle_ForeignKey(i) + else: + raise ValueError("Cannot make ForeignKey from "+str(obj)) + + def handle_field(obj, name): + if isinstance(obj, Field): #Check if this is a field + if not isinstance(obj,ForeignKey): obj.set_name(name) + attrs["fields"].append(obj) + return True + elif name == "ForeignKey": + handle_ForeignKey(obj) + return True + return False + + # loop through the attributes, and take out the fields. + for key in attrs.keys()[:]: + if handle_field(attrs[key], key): + del attrs[key] # If the attr was added to fields, we want to delete it. + + # Sort the fields, so that they appear in the correct order. + attrs["fields"].sort(lambda x,y: x.creation_counter - y.creation_counter) + # If this model is a subclass of another Model, create an Options # object by first copying the base class's _meta and then updating it # with the overrides from this class. @@ -1551,14 +1585,19 @@ # database level. empty_strings_allowed = True - def __init__(self, name, verbose_name=None, primary_key=False, + # Will be increaced each time a Field object is instanced. Used to + # retain the order of fields. + creation_counter = 0 + + def __init__(self, name=None, verbose_name=None, primary_key=False, maxlength=None, unique=False, blank=False, null=False, db_index=None, core=False, rel=None, default=NOT_PROVIDED, editable=True, prepopulate_from=None, unique_for_date=None, unique_for_month=None, unique_for_year=None, validator_list=None, choices=None, radio_admin=None, help_text=''): self.name = name - self.verbose_name = verbose_name or name.replace('_', ' ') + self.original_verbose_name = verbose_name + self.verbose_name = verbose_name or name and name.replace('_', ' ') self.primary_key = primary_key self.maxlength, self.unique = maxlength, unique self.blank, self.null = blank, null @@ -1583,6 +1622,24 @@ else: self.db_index = db_index + # Increace the creation counter, and save our local copy. + self.creation_counter = Field.creation_counter + Field.creation_counter += 1 + + def set_name(self, name ): + """ + Sets the name, and generates the verbose_name from it if needed. + This function is here for when the name needs to be set later, + (such as if it needs to be obtained from the attribute name that + stores the Field instance.) + """ + if not self.original_verbose_name: + # If the verbose name was originally not specified, we will assume that + # the user intends for the first argument passed to __init__ to be the verbose_name. + self.verbose_name = self.name + + self.name = name + self.verbose_name = self.verbose_name or name and name.replace('_', ' ') + def pre_save(self, obj, value, add): """ Hook for altering the object obj based on the value of this field and }}} | adrian | anonymous | 0 | 1 | 0 | 0 | 0 | 0 |