Django2.0手册: API reference

This document describes the details of the QuerySet API. It builds on the
material presented in the model and database
query
guides, so you’ll probably want to read and
understand those documents before reading this one.

Throughout this reference we’ll use the example Weblog models presented in the database query guide.

When QuerySets are evaluated¶

Internally, a QuerySet can be constructed, filtered, sliced, and generally
passed around without actually hitting the database. No database activity
actually occurs until you do something to evaluate the queryset.

You can evaluate a QuerySet in the following ways:

  • Iteration. A QuerySet is iterable, and it executes its database
    query the first time you iterate over it. For example, this will print
    the headline of all entries in the database:

    for e in Entry.objects.all():
        print(e.headline)
    

    Note: Don’t use this if all you want to do is determine if at least one
    result exists. It’s more efficient to use exists().

  • Slicing. As explained in Limiting QuerySets, a QuerySet can
    be sliced, using Python’s array-slicing syntax. Slicing an unevaluated
    QuerySet usually returns another unevaluated QuerySet, but Django
    will execute the database query if you use the “step” parameter of slice
    syntax, and will return a list. Slicing a QuerySet that has been
    evaluated also returns a list.

    Also note that even though slicing an unevaluated QuerySet returns
    another unevaluated QuerySet, modifying it further (e.g., adding
    more filters, or modifying ordering) is not allowed, since that does not
    translate well into SQL and it would not have a clear meaning either.

  • Pickling/Caching. See the following section for details of what
    is involved when pickling QuerySets. The important thing for the
    purposes of this section is that the results are read from the database.

  • repr(). A QuerySet is evaluated when you call repr() on it.
    This is for convenience in the Python interactive interpreter, so you can
    immediately see your results when using the API interactively.

  • len(). A QuerySet is evaluated when you call len() on it.
    This, as you might expect, returns the length of the result list.

    Note: If you only need to determine the number of records in the set (and
    don’t need the actual objects), it’s much more efficient to handle a count
    at the database level using SQL’s SELECT COUNT(*). Django provides a
    count() method for precisely this reason.

  • list(). Force evaluation of a QuerySet by calling list() on
    it. For example:

    entry_list = list(Entry.objects.all())
    
  • bool(). Testing a QuerySet in a boolean context, such as using
    bool(), or, and or an if statement, will cause the query
    to be executed. If there is at least one result, the QuerySet is
    True, otherwise False. For example:

    if Entry.objects.filter(headline="Test"):
       print("There is at least one Entry with the headline Test")
    

    Note: If you only want to determine if at least one result exists (and don’t
    need the actual objects), it’s more efficient to use exists().

Pickling QuerySets¶

If you pickle a QuerySet, this will force all the results to be loaded
into memory prior to pickling. Pickling is usually used as a precursor to
caching and when the cached queryset is reloaded, you want the results to
already be present and ready for use (reading from the database can take some
time, defeating the purpose of caching). This means that when you unpickle a
QuerySet, it contains the results at the moment it was pickled, rather
than the results that are currently in the database.

If you only want to pickle the necessary information to recreate the
QuerySet from the database at a later time, pickle the query attribute
of the QuerySet. You can then recreate the original QuerySet (without
any results loaded) using some code like this:

>>> import pickle
>>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query            # Restore the original 'query'.

The query attribute is an opaque object. It represents the internals of
the query construction and is not part of the public API. However, it is safe
(and fully supported) to pickle and unpickle the attribute’s contents as
described here.

You can’t share pickles between versions

Pickles of QuerySets are only valid for the version of Django that
was used to generate them. If you generate a pickle using Django
version N, there is no guarantee that pickle will be readable with
Django version N+1. Pickles should not be used as part of a long-term
archival strategy.

Since pickle compatibility errors can be difficult to diagnose, such as
silently corrupted objects, a RuntimeWarning is raised when you try to
unpickle a queryset in a Django version that is different than the one in
which it was pickled.