Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[1.5.X] Fixed #15361 - Documented performance considerations for Quer…

…ySet.get()

Thanks mmcnickle for the patch.

Backport of feaf9f2 from master
  • Loading branch information...
commit ffc649df888ea35d0e6848bf53ee26917fccc27e 1 parent 6b1f731
@timgraham timgraham authored
Showing with 70 additions and 1 deletion.
  1. +35 −0 docs/topics/db/optimization.txt
  2. +35 −1 tests/modeltests/basic/tests.py
View
35 docs/topics/db/optimization.txt
@@ -132,6 +132,41 @@ Write your own :doc:`custom SQL to retrieve data or populate models
</topics/db/sql>`. Use ``django.db.connection.queries`` to find out what Django
is writing for you and start from there.
+Retrieve individual objects using a unique, indexed column
+==========================================================
+
+There are two reasons to use a column with
+:attr:`~django.db.models.Field.unique` or
+:attr:`~django.db.models.Field.db_index` when using
+:meth:`~django.db.models.query.QuerySet.get` to retrieve individual objects.
+First, the query will be quicker because of the underlying database index.
+Also, the query could run much slower if multiple objects match the lookup;
+having a unique constraint on the column guarantees this will never happen.
+
+So using the :ref:`example Weblog models <queryset-model-example>`::
+
+ >>> entry = Entry.objects.get(id=10)
+
+will be quicker than:
+
+ >>> entry = Entry.object.get(headline="News Item Title")
+
+because ``id`` is indexed by the database and is guaranteed to be unique.
+
+Doing the following is potentially quite slow:
+
+ >>> entry = Entry.objects.get(headline__startswith="News")
+
+First of all, `headline` is not indexed, which will make the underlying
+database fetch slower.
+
+Second, the lookup doesn't guarantee that only one object will be returned.
+If the query matches more than one object, it will retrieve and transfer all of
+them from the database. This penalty could be substantial if hundreds or
+thousands of records are returned. The penalty will be compounded if the
+database lives on a separate server, where network overhead and latency also
+play a factor.
+
Retrieve everything at once if you know you will need it
========================================================
View
36 tests/modeltests/basic/tests.py
@@ -2,7 +2,7 @@
from datetime import datetime
-from django.core.exceptions import ObjectDoesNotExist
+from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db.models.fields import Field, FieldDoesNotExist
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils import six
@@ -128,6 +128,40 @@ def test_lookup(self):
b = Article.objects.get(pk=a.id)
self.assertEqual(a, b)
+ # Create a very similar object
+ a = Article(
+ id=None,
+ headline='Area man programs in Python',
+ pub_date=datetime(2005, 7, 28),
+ )
+ a.save()
+
+ self.assertEqual(Article.objects.count(), 2)
+
+ # Django raises an Article.MultipleObjectsReturned exception if the
+ # lookup matches more than one object
+ self.assertRaisesRegexp(
+ MultipleObjectsReturned,
+ "get\(\) returned more than one Article -- it returned 2!",
+ Article.objects.get,
+ headline__startswith='Area',
+ )
+
+ self.assertRaisesRegexp(
+ MultipleObjectsReturned,
+ "get\(\) returned more than one Article -- it returned 2!",
+ Article.objects.get,
+ pub_date__year=2005,
+ )
+
+ self.assertRaisesRegexp(
+ MultipleObjectsReturned,
+ "get\(\) returned more than one Article -- it returned 2!",
+ Article.objects.get,
+ pub_date__year=2005,
+ pub_date__month=7,
+ )
+
def test_object_creation(self):
# Create an Article.
a = Article(
Please sign in to comment.
Something went wrong with that request. Please try again.