Opened 15 years ago

Closed 15 years ago

Last modified 13 years ago

#91 closed enhancement (duplicate)

A (possible) cleaner ORM fields description

Reported by: mmarshall Owned by: Adrian Holovaty
Component: Core (Other) Version:
Severity: normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


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.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/
--- django/core/ (revision 227)
+++ django/core/ (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!

Change History (4)

comment:1 Changed 15 years ago by anonymous

Resolution: wontfix
Status: newclosed

comment:2 Changed 15 years ago by Adrian Holovaty

I'm not sure who closed this ticket, but it's still under consideration. See the discussion here:

comment:3 Changed 15 years ago by Jacob

Resolution: wontfix
Status: closedreopened

comment:4 Changed 15 years ago by Adrian Holovaty

Resolution: duplicate
Status: reopenedclosed

I'm closing this ticket, because discussion has moved to #122.

Note: See TracTickets for help on using tickets.
Back to Top