QuerySet API Reference - Django Documentation

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().

  • Asynchronous iteration.. A QuerySet can also be iterated over using async for:

    async for e in Entry.objects.all(): results.append(e)

    Both synchronous and asynchronous iterators of QuerySets share the same underlying cache.

    Changed in Django 4.1:

    Support for asynchronous iteration was added.

  • 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 QuerySet

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.

Restrictions on QuerySet.values_list()

If you recreate QuerySet.values_list() using the pickled query attribute, it will be converted to QuerySet.values():

>>> import pickle >>> qs = Blog.objects.values_list('id', 'name') >>> qs <QuerySet [(1, 'Beatles Blog')]> >>> reloaded_qs = Blog.objects.all() >>> reloaded_qs.query = pickle.loads(pickle.dumps(qs.query)) >>> reloaded_qs <QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

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.

Từ khóa » đan Ts