Code


Version 20 (modified by adrian, 8 years ago) (diff)

--

Fields as descriptors

This proposal changes the Django database API substantially.

Lookup typeOld syntaxNew syntax
Foreign keyarticle.get_reporter()article.reporter
Foreign key fieldarticle.reporter_id (Doesn't do a DB query)article.reporter.id (Doesn't do a DB query)
Foreign key (other end)reporter.get_article_list()reporter.article_set
Foreign key (other end)reporter.get_article_list(headline__startswith="This")reporter.article_set.filter(headline__startswith="This")
Adding related objectsreporter.add_article(headline="John's second story", pub_date=datetime(2005, 7, 29))reporter.article_set.add(headline="John's second story", pub_date=datetime(2005, 7, 29))
Many-to-manyarticle.get_site_list()article.site_set
Many-to-many (adding)article.set_sites([s1.id, s2.id])article.site_set.clear(); article.site_set.add(s1); article.site_set.add(s2);
Many-to-many (deleting)article.set_sites([s1.id])article.site_set.remove(s2)
Orderingreporter.get_article_list(order_by=['headline'])reporter.article_set.order_by('headline')

Implementation details:

  • Fields 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 Reporter.name 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.
  • 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.

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

  • .filter(): adds query parameters using Django's 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].