﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
91	A (possible) cleaner ORM fields description	mmarshall	Adrian Holovaty	"Here is a cleaner approach to the ORM fields.  Using this patch, the example in the tutorial can be changed to this:

{{{
from django.core.meta import Model

# Create your models here.
class Poll(Model):
    def fields(Field):
        Field.Char('question',  maxlength=200)
        Field.DateTime('pub_date', 'date published')

class Choice(Model):
    def fields(Field):
        Field.ForeignKey(Poll)
        Field.Char('choice', 'choice', maxlength=200, core=True)
        Field.Integer('votes', 'votes', core=True)

}}}


I have done an implementation, which is fully backwards compatible, and quite simple.

{{{
Index: django/core/meta.py
===================================================================
--- django/core/meta.py (revision 227)
+++ django/core/meta.py (working copy)
@@ -377,12 +377,53 @@
             new_v.func_globals[k] = func
         new_functions[k] = func

+
+class FieldGenerator(object):
+    """"""FieldGenerator is used for... uh... Generating fields. It has attributes,
+    such as ""Char"" and ""DateTime"", that can be used to create class instances such as
+    ""CharField"" or ""DateTimeField"".  These instances are then added to the list ""fields"",
+    which can be retrieved to be used as the ""fields"" attribute in a Model class.""""""
+    def __init__(self):
+        self.fields = []
+        self.last_class = None #This is the class obj that corrisponds to the last __getattr__ call.
+
+    def __getattr__(self,name):
+        self.last_class = None
+        try:
+            obj = eval(name+""Field"")
+            if issubclass(obj,Field): self.last_class = obj
+        except NameError: pass
+        if not self.last_class: # If name+""Field"" didn't work, just try name.
+            try:
+                obj = eval(name)
+                if issubclass(obj,Field): self.last_class = obj
+            except NameError: pass
+        if not self.last_class:
+            raise AttributeError(""Could not find either %s or %sField (or they are not decendants of Field.)"" % (name,name))
+        return self.GenerateField
+
+    def GenerateField(self, *args, **kargs):
+        """""" This creates an instance of the class corrisponding to the
+        last __getattr__ call, and adds it to self.fields.""""""
+        if not self.last_class:
+            raise ValueError(""GenerateField should only be called with self.last_class set."")
+        self.fields.append(self.last_class(*args, **kargs))
+        self.last_class = None
+
+
 class ModelBase(type):
     ""Metaclass for all models""
     def __new__(cls, name, bases, attrs):
         # If this isn't a subclass of Model, don't do anything special.
         if not bases:
             return type.__new__(cls, name, bases, attrs)
+
+        # If 'fields' is callable, we want to call it, passing a FieldGenerator.
+        if callable(attrs['fields']):
+                fg = FieldGenerator()
+                attrs['fields'](fg)
+                attrs['fields'] = fg.fields

         # 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
}}}


I don't know if this is the best way of doing it... but it's out there!"	enhancement	closed	Core (Other)		normal	duplicate			Accepted	0	0	0	0	0	0
