I'm gonna ignore comparsions beetween Django and Zope about the schema defintion, since the former uses a relational DB as backned while the latter uses a OODB, but Subway (hence SQLObject) approach has some vitues that would be cool to port to Django.
The model in Django is a lot more feature-rich than the Subway one and it's desiderable to avoid name clashes between fields, so it would be good to have a way to wrap fields into a private namespace. Taking the tutorial example, i was wondering if something like this could work:
from django.core import meta
class Poll(meta.Model):
class fields(object): question = meta.CharField('question', maxlength=200) pub_date = meta.DateTimeField('date published')
# but how do we handle FK?
it reads better, the a = b pattern looks more natural to my pythonic eyes. I can tell immediately where are the fields available, just look on the left. actually i don't known how hard is to change current ORM code to play well with the new approach, but i would like to brought up the point.
> class Poll(meta.Model): > class fields(object): > question = meta.CharField('question', maxlength=200) > pub_date = meta.DateTimeField('date published')
> # but how do we handle FK?
I agree that this is prettier and more readable, and, for the record, I'm 100% open to changing model syntax at this point, with no regard for backwards compatibility. (We at World Online will manually convert our dozens of models to the new syntax if need be -- and we're the only people using Django in production at this point.)
Once we have our first public release, our intention is to be backwards-compatible from that point. So now is the time to make these design decisions.
Although it's prettier, your proposal has a few interesting problems:
* As you pointed out, how does it handle ForeignKey()? * "class fields(object):" is crufty
That is, use leading underscores on non-field attributes. It's kind of ugly/crufty. Is it worth changing? Any other ideas?
Also, I'll just throw out there that it would be possible to have different model syntaxes, using subclasses:
class Poll(meta.LeanModel): question = meta.CharField(maxlength=200) pub_date = meta.DateTimeField()
class Poll(meta.DictFieldModel): dict_fields = { 'question': meta.CharField(maxlength=200), 'pub_date': meta.DateTimeField(), }
This blatantly goes against Python's "One obvious way to do it" philosophy, but we might use this technique to support old models as a stop gap -- i.e., if we change model syntax, we can tell people to change their model subclasses to "meta.OldModel" as an immediate fix, before they have time to convert models to the "real" new model syntax.
> That is, use leading underscores on non-field attributes. It's kind of > ugly/crufty. Is it worth changing? Any other ideas?
What about this:
class Poll(meta.Model) # your models fields go here question = meta.CharField(maxlength=200) pub_date = meta.DateTimeField()
# Django specific config goes here. (No icky underscores.) class metadata(): admin = meta.Admin(...) ordering = [('pub_date', 'DESC')]
As a bonus suggestion:
To add fuel to the fire, this would give you a viewable model in your web browser without any extra code required (when quickstarting newbies the first time):
class Poll(meta.Model): use_scaffolding = True # :-)
I am not sure what to think about the proposed solutions, but I do have another idea to throw out there:
import django.core.meta as meta
import django.core.meta.field as field
class Poll(meta.Model):
def fields():
field.Char('question', maxlength=200)
field.DateTime('pub_date', 'date published')
class Choice(meta.Model):
def fields():
field.ForeignKey(Poll)
field.Char('choice', maxlength=200)
field.Integer('votes')
IMHO, this looks pretty clean. It would take a few tricks to implement, however.
The idea would be, that before fields() is called, sys.stdio (or wherever print writes to... I cannot remember) is replaced so that it is captured.
The field.* are functions, which return a string that can be exec()'ed to create the old meta.*Field classes.
Just some fuel for thought... probably could use some work.
> class Poll(meta.Model) > # your models fields go here > question = meta.CharField(maxlength=200) > pub_date = meta.DateTimeField()
> # Django specific config goes here. (No icky underscores.) > class metadata(): > admin = meta.Admin(...) > ordering = [('pub_date', 'DESC')]
you guys might already known it, but this approach is what recent SQLObject revisions uses (post 0.6.1), developers removed underscored prefixed "special" names and wrapped into a "sqlmeta" class. for example:
class Entry(SQLModel):
class sqlmeta(object): table = 'entry' # explicit table name
class Poll:
CharField('question', maxlength=200)
DateTimeField('date published')
Model(Poll)
Is better...
Anyhow, it's sorta hacky is the problem.
What you do is have the *Fields as generator functions,
and a variable in django.core.fields holds a list of created fields.
And then Model would grab that list, apply the fields to the passed in
class, and then empty the list for the next group.
And now that I think of it, you couldn't do:
class Poll:
etc...
class Choice:
etc...
Model(Poll)
Model(Choice)
Which a lot of people would try doin'.
On 7/19/05, Matthew Marshall <mmarsh...@myrealbox.com> wrote:
deelan wrote: > you guys might already known it, but this approach is what recent > SQLObject revisions uses (post 0.6.1), developers removed underscored > prefixed "special" names and wrapped into a "sqlmeta" class. for > example:
Ahh.. I didn't know that about SQLObject > 0.6.1 (I've only played around with 0.6.1).
Sounds like that myth about the 100th monkey. :-) All converging on the same good idea.
The biggest problem I can see here, is the 'Model(Poll)' line. (aside from requiring global variables.) What do you think about this:
from django.core.fields.meta import Model
class Poll(Model):
def fields(Field):
Field.Char('question', maxlength=200)
Field.DateTime('pub_date', 'date_published')
'Field' would be an object, with functions that generate the meta.*Field instances, and put them into a list. This list would then be assigned (internally) to self.fields.
This would be 100% backwards compatible, and almost trivial to implement. I might just go and make a patch now... just for fun.
MWM
On Tuesday 19 July 2005 06:51 pm, Brant Harris wrote:
> Anyhow, it's sorta hacky is the problem.
> What you do is have the *Fields as generator functions,
> and a variable in django.core.fields holds a list of created fields.
> And then Model would grab that list, apply the fields to the passed in
> class, and then empty the list for the next group.
> And now that I think of it, you couldn't do:
> class Poll:
> etc...
> class Choice:
> etc...
> Model(Poll)
> Model(Choice)
> Which a lot of people would try doin'.
> On 7/19/05, Matthew Marshall <mmarsh...@myrealbox.com> wrote:
> > On Tuesday 19 July 2005 05:41 pm, deadwis...@gmail.com wrote:
> > > Let me just put my idea out. I think it is the cleanest.
> > Well, AFAIK decorators only apply to functions, but other than that...
> > I think this looks best too, but I don't see any way to implement it. Am
> > I missing something? Won't whatever was returned by the classes be lost?