Changes between Version 18 and Version 19 of DescriptorFields


Ignore:
Timestamp:
01/16/06 17:01:22 (9 years ago)
Author:
adrian
Comment:

Added example table so people can easily see what's changing.

Legend:

Unmodified
Added
Removed
Modified
  • DescriptorFields

    v18 v19  
    1 = Fields as Descriptors =
     1= Fields as descriptors =
    22
    3 In this proposal, fields would become descriptors.
     3This proposal changes the Django database API substantially.
    44 
    5 This means
     5||Lookup type||Old syntax||New syntax||
     6||Foreign key||{{{article.get_reporter()}}}||{{{article.reporter}}}||
     7||Foreign key field||{{{article.reporter_id}}} (Doesn't do a DB query)||{{{article.reporter.id}}} (Doesn't do a DB query)||
     8||Foreign key (other end)||{{{reporter.get_article_list()}}}||{{{reporter.article_set}}}||
     9||Foreign key (other end)||{{{reporter.get_article_list(headline__startswith="This")}}}||{{{reporter.article_set.filter(headline__startswith="This")}}}||
     10||Adding related objects||{{{reporter.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))}}}||
     11||Many-to-many||{{{article.get_site_list()}}}||{{{article.site_set}}}||
     12||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);}}}||
     13||Many-to-many (deleting)||{{{article.set_sites([s1.id])}}}||{{{article.site_set.remove(s2)}}}||
     14||Ordering||{{{reporter.get_article_list(order_by=['headline'])}}}||{{{reporter.article_set.order_by('headline')}}}||
    615
    7  * They would be left as members by the metaclass.
     16
     17Implementation details:
     18
     19 * Fields would be left as members by the metaclass.
    820 * The real 'data' would end up either in name-mangled instance members, or in a private dictionary.
    921 * When accessed via the class, they would return themselves. eg
     
    1426   - the simple data instance from the private dict that was fetched from the db.
    1527   - 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.
    16    For a ForeignKey,
    17 
    18    {{{
    19      article.get_reporter()
    20      article.reporter_id
    21    }}}
    22 
    23    would change to:
    24    {{{
    25      article.reporter
    26      article.reporter.id
    27    }}}
    2828
    2929 * ForeignKeys and other related fields would place another descriptor on the related class.
     
    3232   
    3333   This would also support other methods in favour of the get_related_list things.
    34    
    35    Other end of ForeignKey! relationship:
    36    
    37    {{{
    38     reporter.get_article_list()
    39     reporter.get_article_list(headline__startswith='This', order_by=['headline'])
    40     reporter.add_article(headline="John's second story", pub_date=datetime(2005, 7, 29))
    41    }}}
    42    would change to:
    43    {{{
    44     reporter.article_set
    45     reporter.article_set.filter(headline__startswith='This').order_by('headline')
    46     reporter.article_set.add(headline="John's second story", pub_date=datetime(2005, 7, 29))
    47    }}}
    4834 
    4935   Methods which change the meaning of the lazy collection are as follows:
     
    5642   Sometimes, multiple queries will be used to save traffic, eg if you access reporter.article_set[10000:10020] and then reporter.article_set[:20].
    5743
    58    Other methods of a similar style are also possible.
    59 
    60    - .add would add a new instance of the related class to the collection.
    61      This would register a callback so that it would be written to the db when .save() is called on the parent object.
    62 
    63    ManyToMany examples: (from http://www.djangoproject.com/documentation/models/many_to_many/ )
    64  
    65    {{{
    66        a1.set_publications([p1.id])
    67    }}}     
    68 
    69    goes to 
    70 
    71    {{{   
    72           a1.publication_set.clear()
    73           a1.publication_set.add(p1)
    74    }}}
    75 
    76    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.
    77    
    78 ----
    79 
    80    {{{
    81           a2.set_publications([p1.id])
    82           a2.set_publications([p1.id, p2.id])
    83    }}}
    84 
    85    goes to
    86 
    87    {{{ 
    88           a2.publication_set.clear()
    89           a2.publication_set.add(p1)
    90           a2.publication_set.clear()
    91           a2.publication_set.update([p1,p2])
    92    }}}
    93 
    94    or idiomatically
    95 
    96    {{{
    97          a2.publication_set.clear()
    98          a2.publication_set.add(p1)
    99          a2.publication_set.add(p2)
    100    }}}
    101 
    102 
    103 
    104 ----
    105 
    106    {{{
    107      p1.get_article_list(order_by=['headline'])
    108    }}}
    109 
    110    goes to
    111 
    112    {{{
    113      p1.article_set.order_by('headline')
    114    }}}
    115 
    116 ----
    117 = Query Syntax =
     44== Query syntax ==
    11845
    11946In further discussions about this idea, it seemed consistent that both the manager ( Person.objects ) and relationship end points, ({{{reporter.articles}}}) would act as lazy sets of instances (base class QuerySet?) , with these 'refinement' methods on them (filter, order_by, etc).
     
    13865ar_set = people.filter(name_startswith="R") | people.filter(name_startswith="A")
    13966}}}
    140 
    141 
    142 
    143 ----
    144 
    145 ''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: http://projects.amor.org/dejavu/browser/trunk/units.py  -- Robert Brewer''
    146 
    147 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 .
    148 
    149 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
    150 
    151 eg,
    152 
    153 {{{
    154 simons = Person.objects.filter(name_startswith="Simon")
    155 
    156 for simon in simons: <--- hits database
    157    pass
    158 
    159 for simon in simons: <--- uses cache
    160    pass
    161 
    162 }}}
Back to Top