Changes between Version 23 and Version 24 of DescriptorFields


Ignore:
Timestamp:
01/25/2006 09:54:50 PM (10 years ago)
Author:
adrian
Comment:

Refactored page

Legend:

Unmodified
Added
Removed
Modified
  • DescriptorFields

    v23 v24  
    22
    33This proposal changes the Django database API substantially.
    4  
    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, count)||{{{reporter.get_article_count()}}}||{{{reporter.article_set.count()}}}||
    10 ||Foreign key (other end)||{{{reporter.get_article_list(headline__startswith="This")}}}||{{{reporter.article_set.filter(headline__startswith="This")}}}||
    11 ||Distinct||{{{reporters.get_list(distinct=True)}}}||{{{Reporter.objects.distinct()}}}||
    12 ||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))}}}||
    13 ||Many-to-many||{{{article.get_site_list()}}}||{{{article.site_set}}}||
    14 ||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);}}}||
    15 ||Many-to-many (deleting)||{{{article.set_sites([s1.id])}}}||{{{article.site_set.remove(s2)}}}||
    16 ||Ordering||{{{reporter.get_article_list(order_by=['headline'])}}}||{{{reporter.article_set.order_by('headline')}}}||
    174
     5The examples on this page use the following models:
    186
    19 Implementation details:
     7{{{
     8#!python
     9class Reporter(models.Model):
     10    fname = models.CharField(maxlength=30)
     11    lname = models.CharField(maxlength=30)
    2012
    21  * Fields would be left as members by the metaclass.
    22  * The real 'data' would end up either in name-mangled instance members, or in a private dictionary.
    23  * When accessed via the class, they would return themselves. eg
    24    Reporter.name would be a field class you can inspect. This would make introspection as in the admin easier.
     13class Site(models.Model):
     14    name = models.CharField(maxlength=20)
    2515
    26  * When accessed via the instance, they would return a representation of the value they
    27    hold. This could be
    28    - the simple data instance from the private dict that was fetched from the DB.
    29    - 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.
     16class Article(models.Model):
     17    headline = models.CharField(maxlength=50)
     18    reporter = models.ForeignKey(Reporter)
     19    sites = models.ManyToManyField(Site)
     20}}}
    3021
    31  * !ForeignKeys and other related fields would place another descriptor on the related class.
    32    When accessed via the instance, this would return a lazy collection object. It will act like a set
    33    (an ordered one if there is an ordering involved). 
    34    
    35    This would also support other methods in favor of the get_related_list things.
    36  
    37    Methods which change the meaning of the lazy collection are as follows:
    38  
    39    * {{{.filter()}}}: adds query parameters using Django's normal DB query syntax.
    40    * {{{.order_by()}}}: adds/changes ordering parameters.
     22== Overview ==
    4123
    42    The collection supports the appropriate collection protocols: It acts as a set, with ordering
    43    if there is an ordering in the underlying query. The query is only done when a collection protocol is used.
    44    Sometimes, multiple queries will be used to save traffic, eg if you access reporter.article_set[10000:10020] and then reporter.article_set[:20].
     24This proposal changes the way foreign-key and many-to-many related objects are accessed via the database-object API. It also changes the functionality of {{{get_list()}}}, {{{get_object()}}}, etc.
     25
     26Under this proposal, each manager gets the following methods:
     27
     28{{{
     29#!python
     30class Manager:
     31    def all(self):
     32        # returns a Query instance -- old get_list()
     33
     34    def filter(self, **kwargs):
     35        # returns a Query instance -- old get_list(**kwargs)
     36
     37    def get(self, **kwargs):
     38        # returns a Query instance -- old get_object()
     39
     40    def values(self, **kwargs):
     41        # returns a ValuesQuery instance -- old get_values()
     42
     43    def in_bulk(self, **kwargs):
     44        # return an InBulkQuery instance -- old get_in_bulk()
     45
     46class Query:
     47    def filter(self, **kwargs):
     48        # returns a Query instance
     49
     50    def unique(self, true_or_false):
     51        # returns a Query instance
     52
     53    def order_by(self, *field_names):
     54        # returns a Query instance
     55
     56    def count(self):
     57        # returns a Query instance
     58
     59class ValuesQuery(Query):
     60    # Only difference is the output format.
     61
     62class InBulkQuery(Query):
     63    # Only difference is the output format.
     64
     65}}}
     66
     67Any of these Manager methods can be overridden by custom managers, of course.
     68
     69Related-object lookup uses the default manager of the related object, which means the API for accessing related objects is completely consistent with the API for accessing objects via a manager.
     70
     71Another improvement is that the lookup type {{{__exact}}} can be left off.
     72
     73== Examples ==
     74
     75|| Old syntax                                              || New syntax                                   ||
     76|| Reporter.objects.get_list()                             || Reporter.objects.all()                       ||
     77|| Reporter.objects.get_list(fname__exact='John')          || Reporter.objects.filter(fname='John')        ||
     78|| Reporter.objects.get_list(order_by=('-lname', 'fname')) || Reporter.objects.order_by('-lname', 'fname') ||
     79|| Reporter.objects.get_list(fname__exact='John', order_by=('lname',)) || Reporter.objects.filter(fname='John').order_by('lname') ||
     80|| Reporter.objects.get_object(pk=3)                       || Reporter.objects.get(pk=3)                   ||
     81|| Reporter.objects.get_object(fname__contains='John')     || Reporter.objects.get(fname__contains='John') ||
     82|| Reporter.objects.get_list(distinct=True)                || Reporter.objects.all().distinct() ||
     83|| Reporter.objects.get_values()                           || Reporter.objects.values() ||
     84|| Reporter.objects.get_in_bulk([1, 2])                    || Reporter.objects.in_bulk([1, 2]) ||
     85|| Reporter.objects.get_in_bulk([1, 2], fname__exact='John') || Reporter.objects.filter(fname='John').in_bulk([1, 2]) ||
     86|| '''Many-to-one related lookup'''                        ||                                              ||
     87|| article_obj.reporter_id                                 || article_obj.reporter.id ||
     88|| article_obj.get_reporter()                              || article_obj.reporter    ||
     89|| reporter_obj.get_article_list()                         || reporter_obj.article_set.all() ||
     90|| reporter_obj.get_article_list(headline__exact='Hello')  || reporter_obj.article_set.filter(headline='Hello') ||
     91|| reporter_obj.get_article_count()                        || reporter_obj.article_set.count() ||
     92|| reporter_obj.add_article(headline='Foo')                || reporter_obj.article_set.add(headline='Foo') ||
     93|| (Alternate syntax)                                      || reporter_obj.article_set.add(article_obj) ||
     94|| ("values" lookup, etc., not previously possible)        || reporter_obj.article_set.values() ||
     95|| '''Many-to-many related lookup'''                       ||                         ||
     96|| article_obj.get_site_list()                             || article_obj.site_set.all() ||
     97|| article_obj.set_sites([s1.id, s2.id])                   || article_obj.site_set.clear(); article_obj.site_set.add(s1); article_obj.site_set.add(s2) ||
     98|| article_obj.set_sites([s1.id]) # deletion               || article_obj.site_set.remove(s2) ||
     99|| site_obj.get_reporter_list()                            || site_obj.reporter_set.all() ||
     100
Back to Top