From 26c6566215ebc9407f3c40643ff907ac5084f3c1 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Thu, 14 Jul 2005 19:25:13 +0000 Subject: [PATCH] Made some changes to db-api docs git-svn-id: http://code.djangoproject.com/svn/django/trunk@32 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/db-api.txt | 130 ++++++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 48 deletions(-) diff --git a/docs/db-api.txt b/docs/db-api.txt index aebfd36cfa..b97018b46e 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -4,12 +4,9 @@ Database API reference XXX INTRO HERE XXX -Throughout this reference, I'll be referring to the following Poll application:: +Throughout this reference, we'll refer to the following Poll application:: class Poll(meta.Model): - module_name = 'polls' - verbose_name = 'poll' - db_table = 'polls' fields = ( meta.SlugField('slug', 'slug', unique_for_month='pub_date'), meta.CharField('question', 'question', maxlength=255), @@ -18,13 +15,9 @@ Throughout this reference, I'll be referring to the following Poll application:: ) class Choice(meta.Model): - module_name = 'choices' - verbose_name = 'choice' - db_table = 'poll_choices' fields = ( - meta.IntegerField('poll_id', 'poll', rel=meta.ManyToOne(Poll, 'poll', 'id', - edit_inline=True, edit_inline_type=meta.TABULAR, num_in_admin=10, - min_num_in_admin=5)), + meta.ForeignKey(Poll, edit_inline=True, edit_inline_type=meta.TABULAR, + num_in_admin=10, min_num_in_admin=5), meta.CharField('choice', 'choice', maxlength=255, core=True), meta.IntegerField('votes', 'votes', editable=False, default=0), ) @@ -35,8 +28,8 @@ Basic lookup functions Each model exposes three basic functions for lookups: ``get_object``, ``get_list``, and ``get_count``. These functions all take the same arguments, but ``get_object`` assumes that only a single record will be returned (and -raises an exception if that's not true), ``get_count`` simple returns a count of -objects matched by the lookup, and ``get_list`` returns the entire list. +raises ``AssertionError`` if that's not true), ``get_count`` simply returns a +count of objects matched by the lookup, and ``get_list`` returns a list of objects. Field lookups ============= @@ -48,7 +41,7 @@ double-underscore). For example:: translates (roughly) into the following SQL: - SELECT * FROM polls WHERE pub_date < NOW(); + SELECT * FROM polls_polls WHERE pub_date < NOW(); The DB API supports the following lookup types: @@ -59,10 +52,10 @@ The DB API supports the following lookup types: iexact Case-insensitive exact match: ``polls.get_list(slug__iexact="foo")`` matches a slug of ``foo``, ``FOO``, ``fOo``, etc. - contains Case-sensitive contains test: + contains Case-sensitive containment test: ``polls.get_list(question__contains="spam")`` returns all polls that contain "spam" in the question. - icontains Case-insensitive contains + icontains Case-insensitive containment test gt Greater than: ``polls.get_list(id__gt=4)`` gte Greater than or equal to lt Less than @@ -71,7 +64,7 @@ The DB API supports the following lookup types: ``polls.get_list(question_startswith="Would")`` endswith Case-sensitive ends-with range Range test: - ``polls.get_list(pub_date__range=(start_date, end_date)`` + ``polls.get_list(pub_date__range=(start_date, end_date))`` returns all polls with a pub_date between ``start_date`` and ``end_date`` (inclusive). year For date/datetime fields, exact year match: @@ -82,7 +75,7 @@ The DB API supports the following lookup types: ``polls.get_list(expire_date__isnull=True)``. ========== ============================================================== -Multiple lookups are of course allowed, and are translated as "ands":: +Multiple lookups are allowed, of course, and are translated as "AND"s:: polls.get_list( pub_date__year=2005, @@ -90,11 +83,7 @@ Multiple lookups are of course allowed, and are translated as "ands":: question__startswith="Would", ) -retrieves all polls published in Jan. 2005 whose question starts with "Would." - -"Or" lookups are also possible:: - - XXX FIXME XXX +...retrieves all polls published in January 2005 that have a question starting with "Would." Ordering ======== @@ -112,7 +101,7 @@ provided by the ``order_by`` argument to a lookup:: The result set above will be ordered by ``pub_date`` (descending), then by ``question`` (ascending). Just like in models, the ``order_by`` clause is a list of ordering tuples where the first element is the field and the -second is "ASC" or "DESC" to order ascending or descending. You may also +second is "ASC" (ascending) or "DESC" (descending). You can also use the tuple ``(None, "RANDOM")`` to order the result set randomly. Relationships (joins) @@ -123,14 +112,14 @@ Joins may implicitly be performed by following relationships: objects where the associated ``Poll`` has a slug of ``eggs``. Multiple levels of joins are allowed. -Given an instance of an object, related objects can be looked up directly using -connivence functions, for example, if ``poll`` is a ``Poll`` instance, -``poll.get_choice_list()`` will return a list of all associated choices (astute +Given an instance of an object, related objects can be looked-up directly using +convenience functions. For example, if ``p`` is a ``Poll`` instance, +``p.get_choice_list()`` will return a list of all associated choices. Astute readers will note that this is the same as -``choices.get_list(poll_id__exact=poll.id)``, except clearer). +``choices.get_list(poll_id__exact=p.id)``, except clearer. Each type of relationship creates a set of methods on each object in the -relationship. These created methods go both ways, so objects that are +relationship. These methods are created in both directions, so objects that are "related-to" need not explicitly define reverse relationships; that happens automatically. @@ -141,7 +130,6 @@ Each object in a one-to-one relationship will have a ``get_relatedobject()`` method. For example:: class Place(meta.Model): - ... fields = ( ... ) @@ -160,23 +148,29 @@ and each ``Restaurant`` will have a ``get_place()`` method. Many-to-one relations --------------------- -In each many-to-one relationship the related object will have a +In each many-to-one relationship, the related object will have a ``get_relatedobject()`` method, and the related-to object will have ``get_relatedobject()``, ``get_relatedobject_list()``, and ``get_relatedobject_count()`` methods (the same as the module-level ``get_object()``, ``get_list()``, and ``get_count()`` methods). -Thus, for the ``Poll`` example at the top, ``Choice`` objects will have a -``get_poll()`` method, and ``Poll`` objects will have ``get_choice()``, -``get_choice_list()``, and ``get_choice_count()`` functions. +In the poll example above, here are the available choice methods on a ``Poll`` object ``p``:: + + p.get_choice() + p.get_choice_list() + p.get_choice_count() + +And a ``Choice`` object ``c`` has the following method:: + + c.get_poll() Many-to-many relations ---------------------- Many-to-many relations result in the same set of methods as `Many-to-one relations`_, -except that the ``get_relatedobjects()`` function on the related object will +except that the ``get_relatedobject_list()`` function on the related object will return a list of instances instead of a single instance. So, if the relationship -between ``Poll`` and ``Choice`` was many-to-many, ``choice.get_polls()`` would +between ``Poll`` and ``Choice`` was many-to-many, ``choice.get_poll_list()`` would return a list. Relationships across applications @@ -192,10 +186,9 @@ Selecting related objects Relations are the bread and butter of databases, so there's an option to "follow" all relationships and pre-fill them in a simple cache so that later calls to -objects with a one-to-many relationship don't have to hit the database. If you pass -``select_related=True`` to a lookup, this pre-caching of relationships will be performed. -This results in (sometimes much) larger queries, but it means that later use of -relationships is much faster. +objects with a one-to-many relationship don't have to hit the database. Do this by +passing ``select_related=True`` to a lookup. This results in (sometimes much) larger +queries, but it means that later use of relationships is much faster. For example, using the Poll and Choice models from above, if you do the following:: @@ -203,6 +196,35 @@ For example, using the Poll and Choice models from above, if you do the followin Then subsequent calls to ``c.get_poll()`` won't hit the database. +Note that ``select_related`` follows foreign keys as far as possible. If you have the +following models... + + class Poll(meta.Model): + ... + + class Choice(meta.Model): + fields = ( + meta.ForeignKey(Poll), + ... + ) + + class SingleVote(meta.Model): + fields = ( + meta.ForeignKey(Choice), + ... + ) + +...then a call to ``singlevotes.get_object(id__exact=4, select_related=True)`` will +cache the related choice *and* the related poll. + + >>> sv = singlevotes.get_object(id__exact=4, select_related=True) + >>> c = sv.get_choice() # Doesn't hit the database. + >>> p = c.get_poll() # Doesn't hit the database. + + >>> sv = singlevotes.get_object(id__exact=4) # Note no "select_related". + >>> c = sv.get_choice() # Hits the database. + >>> p = c.get_poll() # Hits the database. + Limiting selected rows ====================== @@ -210,16 +232,16 @@ The ``limit``, ``offset``, and ``distinct`` keywords can be used to control which rows are returned. Both ``limit`` and ``offset`` should be integers which will be directly passed to the SQL ``LIMIT``/``OFFSET`` commands. -If ``distinct`` is True, only distinct rows will be returned (this is equivalent -to a ``SELECT DISTINCT`` SQL clause). +If ``distinct`` is True, only distinct rows will be returned. This is equivalent +to a ``SELECT DISTINCT`` SQL clause. Other lookup options ==================== There are a few other ways of more directly controlling the generated SQL for the lookup. Note that by definition these extra lookups may not be -portable to different database engines (since you're explicitly writing -SQL code) and should be avoided where ever possible.: +portable to different database engines (because you're explicitly writing +SQL code) and should be avoided if possible.: ``params`` ---------- @@ -233,16 +255,17 @@ parameters to be substituted. ---------- The ``select`` keyword allows you to select extra fields. This should be a -dict mapping field names to a SQL clause to use for that field. For example:: +dictionary mapping attribute names to a SQL clause to use to calculate that +attribute. For example:: polls.get_list( select={ - 'choice_count' : 'SELECT COUNT(*) FROM choices WHERE poll_id = polls.id' + 'choice_count': 'SELECT COUNT(*) FROM choices WHERE poll_id = polls.id' } ) -Each of the resulting ``Poll`` objects will have an extra ``choice_count`` with -a count of associated ``Choice`` objects. Note that the parenthesis required by +Each of the resulting ``Poll`` objects will have an extra attribute, ``choice_count``, +an integer count of associated ``Choice`` objects. Note that the parenthesis required by most database engines around sub-selects are not required in Django's ``select`` clauses. @@ -250,9 +273,20 @@ clauses. ---------------------- If you need to explicitly pass extra ``WHERE`` clauses -- perhaps to perform -non-explicit joins -- use the ``where`` keyword.. If you need to +non-explicit joins -- use the ``where`` keyword. If you need to join other tables into your query, you can pass their names to ``tables``. +``where`` and ``tables`` both take a list of strings. All ``where`` parameters +are "AND"ed to any other search criteria. + +For example:: + + polls.get_list(question__startswith='Who', where=['id IN (3, 4, 5, 20)']) + +...translates (roughly) into the following SQL: + + SELECT * FROM polls_polls WHERE question LIKE 'Who%' AND id IN (3, 4, 5, 20); + Creating new objects ====================