Version 14 (modified by rjwittams, 11 years ago) (diff)


Fields as Descriptors

In this proposal, fields would become descriptors. This means

  • They would be left as members by the metaclass.
  • The real 'data' would end up either in name-mangled instance members, or in a private dictionary.
  • When accessed via the class, they would return themselves. eg would be a field class you can inspect. This would make introspection as in the admin easier.
  • When accessed via the instance, they would return a representation of the value they hold. This could be
    • the simple data instance from the private dict that was fetched from the db.
    • a lazily computed value, eg a BLOB field which would be fetched from the db on first access, not at initial load time, or a ForeignKey relationship that hasn't been loaded yet. For a ForeignKey,

would change to:

  • ForeignKeys and other related fields would place another descriptor on the related class. When accessed via the instance, this would return a lazy collection object. It will act like a set (an ordered one if there is an ordering involved).

This would also support other methods in favour of the get_related_list things.

Other end of ForeignKey relationship:

 reporter.get_article_list(headline__startswith='This', order_by=['headline'])
 reporter.add_article(headline="John's second story", pub_date=datetime(2005, 7, 29))

would change to:

 reporter.article_set.add(headline="John's second story", pub_date=datetime(2005, 7, 29))

Methods which change the meaning of the lazy collection are as follows:

  • .filter : adds query parameters using djangos normal db query syntax.
  • .order_by: adds/changes ordering parameters.

The collection supports the appropriate collection protocols : It acts as a set, with ordering if there is an ordering in the underlying query. The query is only done when a collection protocol is used. Sometimes, multiple queries will be used to save traffic, eg if you access reporter.article_set[10000:10020] and then reporter.article_set[:20].

Other methods of a similar style are also possible.

  • .add would add a new instance of the related class to the collection. This would register a callback so that it would be written to the db when .save() is called on the parent object.

ManyToMany examples: (from )


goes to


This looks a bit odd because of the clear call . In reality, most of the time you don't want to replace a whole set of many-to-manys, so the new api is more convenient than the old one. The methods are precisely those of a Python 2.4 built in set.


goes to


or idiomatically



goes to


When you finally open a ticket on this massive change ;) I'll add a comment that you should feel free to steal code from Dejavu, which has used descriptors successfully for two years now: -- Robert Brewer

The reason we avoided this in the initial design of Django is that we wanted it to be clear when an action would result in a database query being executed. This explicitness makes it easier to optimise your code - it's obvious when an action will result in an extra query, making it clearer when you should store results in a local variable for later use. -- Simon Willison .

I think the mailing list is better for discussions, but I don't think that you need to worry about the local variable thing. You can still save things in a local variable, exactly as before. The only change is that things will not actually be fetched until required. After that, they will be cached. -- Robert Wittams


simons = Person.objects(name_startswith="Simon")

for simon in simons: <--- hits database

for simon in simons: <--- uses cache

Back to Top