Fixed #30159 -- Removed unneeded use of OrderedDict.

Dicts preserve order since Python 3.6.
This commit is contained in:
Nick Pope 2019-02-05 11:22:08 +00:00 committed by Tim Graham
parent 21bb71ef0d
commit 24b82cd201
31 changed files with 201 additions and 287 deletions

View File

@ -2,7 +2,7 @@ import functools
import sys import sys
import threading import threading
import warnings import warnings
from collections import Counter, OrderedDict, defaultdict from collections import Counter, defaultdict
from functools import partial from functools import partial
from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured
@ -31,10 +31,10 @@ class Apps:
# and whether the registry has been populated. Since it isn't possible # and whether the registry has been populated. Since it isn't possible
# to reimport a module safely (it could reexecute initialization code) # to reimport a module safely (it could reexecute initialization code)
# all_models is never overridden or reset. # all_models is never overridden or reset.
self.all_models = defaultdict(OrderedDict) self.all_models = defaultdict(dict)
# Mapping of labels to AppConfig instances for installed apps. # Mapping of labels to AppConfig instances for installed apps.
self.app_configs = OrderedDict() self.app_configs = {}
# Stack of app_configs. Used to store the current state in # Stack of app_configs. Used to store the current state in
# set_available_apps and set_installed_apps. # set_available_apps and set_installed_apps.
@ -316,10 +316,11 @@ class Apps:
) )
self.stored_app_configs.append(self.app_configs) self.stored_app_configs.append(self.app_configs)
self.app_configs = OrderedDict( self.app_configs = {
(label, app_config) label: app_config
for label, app_config in self.app_configs.items() for label, app_config in self.app_configs.items()
if app_config.name in available) if app_config.name in available
}
self.clear_cache() self.clear_cache()
def unset_available_apps(self): def unset_available_apps(self):
@ -347,7 +348,7 @@ class Apps:
if not self.ready: if not self.ready:
raise AppRegistryNotReady("App registry isn't ready yet.") raise AppRegistryNotReady("App registry isn't ready yet.")
self.stored_app_configs.append(self.app_configs) self.stored_app_configs.append(self.app_configs)
self.app_configs = OrderedDict() self.app_configs = {}
self.apps_ready = self.models_ready = self.loading = self.ready = False self.apps_ready = self.models_ready = self.loading = self.ready = False
self.clear_cache() self.clear_cache()
self.populate(installed) self.populate(installed)

View File

@ -2,7 +2,6 @@ import copy
import json import json
import operator import operator
import re import re
from collections import OrderedDict
from functools import partial, reduce, update_wrapper from functools import partial, reduce, update_wrapper
from urllib.parse import quote as urlquote from urllib.parse import quote as urlquote
@ -682,10 +681,7 @@ class ModelAdmin(BaseModelAdmin):
exclude = exclude or None exclude = exclude or None
# Remove declared form fields which are in readonly_fields. # Remove declared form fields which are in readonly_fields.
new_attrs = OrderedDict.fromkeys( new_attrs = dict.fromkeys(f for f in readonly_fields if f in self.form.declared_fields)
f for f in readonly_fields
if f in self.form.declared_fields
)
form = type(self.form.__name__, (self.form,), new_attrs) form = type(self.form.__name__, (self.form,), new_attrs)
defaults = { defaults = {
@ -886,13 +882,9 @@ class ModelAdmin(BaseModelAdmin):
# If self.actions is set to None that means actions are disabled on # If self.actions is set to None that means actions are disabled on
# this page. # this page.
if self.actions is None or IS_POPUP_VAR in request.GET: if self.actions is None or IS_POPUP_VAR in request.GET:
return OrderedDict() return {}
actions = self._filter_actions_by_permissions(request, self._get_base_actions()) actions = self._filter_actions_by_permissions(request, self._get_base_actions())
# Convert the actions into an OrderedDict keyed by name. return {name: (func, name, desc) for func, name, desc in actions}
return OrderedDict(
(name, (func, name, desc))
for func, name, desc in actions
)
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH):
""" """

View File

@ -1,4 +1,3 @@
from collections import OrderedDict
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.conf import settings from django.conf import settings
@ -361,12 +360,12 @@ class ChangeList:
def get_ordering_field_columns(self): def get_ordering_field_columns(self):
""" """
Return an OrderedDict of ordering field column numbers and asc/desc. Return a dictionary of ordering field column numbers and asc/desc.
""" """
# We must cope with more than one column having the same underlying sort # We must cope with more than one column having the same underlying sort
# field, so we base things on column numbers. # field, so we base things on column numbers.
ordering = self._get_default_ordering() ordering = self._get_default_ordering()
ordering_fields = OrderedDict() ordering_fields = {}
if ORDER_VAR not in self.params: if ORDER_VAR not in self.params:
# for ordering specified on ModelAdmin or model Meta, we don't know # for ordering specified on ModelAdmin or model Meta, we don't know
# the right column numbers absolutely, because there might be more # the right column numbers absolutely, because there might be more

View File

@ -4,7 +4,6 @@ import functools
import hashlib import hashlib
import importlib import importlib
import warnings import warnings
from collections import OrderedDict
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
@ -256,12 +255,12 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
def safe_summary(self, encoded): def safe_summary(self, encoded):
algorithm, iterations, salt, hash = encoded.split('$', 3) algorithm, iterations, salt, hash = encoded.split('$', 3)
assert algorithm == self.algorithm assert algorithm == self.algorithm
return OrderedDict([ return {
(_('algorithm'), algorithm), _('algorithm'): algorithm,
(_('iterations'), iterations), _('iterations'): iterations,
(_('salt'), mask_hash(salt)), _('salt'): mask_hash(salt),
(_('hash'), mask_hash(hash)), _('hash'): mask_hash(hash),
]) }
def must_update(self, encoded): def must_update(self, encoded):
algorithm, iterations, salt, hash = encoded.split('$', 3) algorithm, iterations, salt, hash = encoded.split('$', 3)
@ -330,16 +329,16 @@ class Argon2PasswordHasher(BasePasswordHasher):
(algorithm, variety, version, time_cost, memory_cost, parallelism, (algorithm, variety, version, time_cost, memory_cost, parallelism,
salt, data) = self._decode(encoded) salt, data) = self._decode(encoded)
assert algorithm == self.algorithm assert algorithm == self.algorithm
return OrderedDict([ return {
(_('algorithm'), algorithm), _('algorithm'): algorithm,
(_('variety'), variety), _('variety'): variety,
(_('version'), version), _('version'): version,
(_('memory cost'), memory_cost), _('memory cost'): memory_cost,
(_('time cost'), time_cost), _('time cost'): time_cost,
(_('parallelism'), parallelism), _('parallelism'): parallelism,
(_('salt'), mask_hash(salt)), _('salt'): mask_hash(salt),
(_('hash'), mask_hash(data)), _('hash'): mask_hash(data),
]) }
def must_update(self, encoded): def must_update(self, encoded):
(algorithm, variety, version, time_cost, memory_cost, parallelism, (algorithm, variety, version, time_cost, memory_cost, parallelism,
@ -426,12 +425,12 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
algorithm, empty, algostr, work_factor, data = encoded.split('$', 4) algorithm, empty, algostr, work_factor, data = encoded.split('$', 4)
assert algorithm == self.algorithm assert algorithm == self.algorithm
salt, checksum = data[:22], data[22:] salt, checksum = data[:22], data[22:]
return OrderedDict([ return {
(_('algorithm'), algorithm), _('algorithm'): algorithm,
(_('work factor'), work_factor), _('work factor'): work_factor,
(_('salt'), mask_hash(salt)), _('salt'): mask_hash(salt),
(_('checksum'), mask_hash(checksum)), _('checksum'): mask_hash(checksum),
]) }
def must_update(self, encoded): def must_update(self, encoded):
algorithm, empty, algostr, rounds, data = encoded.split('$', 4) algorithm, empty, algostr, rounds, data = encoded.split('$', 4)
@ -486,11 +485,11 @@ class SHA1PasswordHasher(BasePasswordHasher):
def safe_summary(self, encoded): def safe_summary(self, encoded):
algorithm, salt, hash = encoded.split('$', 2) algorithm, salt, hash = encoded.split('$', 2)
assert algorithm == self.algorithm assert algorithm == self.algorithm
return OrderedDict([ return {
(_('algorithm'), algorithm), _('algorithm'): algorithm,
(_('salt'), mask_hash(salt, show=2)), _('salt'): mask_hash(salt, show=2),
(_('hash'), mask_hash(hash)), _('hash'): mask_hash(hash),
]) }
def harden_runtime(self, password, encoded): def harden_runtime(self, password, encoded):
pass pass
@ -517,11 +516,11 @@ class MD5PasswordHasher(BasePasswordHasher):
def safe_summary(self, encoded): def safe_summary(self, encoded):
algorithm, salt, hash = encoded.split('$', 2) algorithm, salt, hash = encoded.split('$', 2)
assert algorithm == self.algorithm assert algorithm == self.algorithm
return OrderedDict([ return {
(_('algorithm'), algorithm), _('algorithm'): algorithm,
(_('salt'), mask_hash(salt, show=2)), _('salt'): mask_hash(salt, show=2),
(_('hash'), mask_hash(hash)), _('hash'): mask_hash(hash),
]) }
def harden_runtime(self, password, encoded): def harden_runtime(self, password, encoded):
pass pass
@ -553,10 +552,10 @@ class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
def safe_summary(self, encoded): def safe_summary(self, encoded):
assert encoded.startswith('sha1$$') assert encoded.startswith('sha1$$')
hash = encoded[6:] hash = encoded[6:]
return OrderedDict([ return {
(_('algorithm'), self.algorithm), _('algorithm'): self.algorithm,
(_('hash'), mask_hash(hash)), _('hash'): mask_hash(hash),
]) }
def harden_runtime(self, password, encoded): def harden_runtime(self, password, encoded):
pass pass
@ -589,10 +588,10 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
return constant_time_compare(encoded, encoded_2) return constant_time_compare(encoded, encoded_2)
def safe_summary(self, encoded): def safe_summary(self, encoded):
return OrderedDict([ return {
(_('algorithm'), self.algorithm), _('algorithm'): self.algorithm,
(_('hash'), mask_hash(encoded, show=3)), _('hash'): mask_hash(encoded, show=3),
]) }
def harden_runtime(self, password, encoded): def harden_runtime(self, password, encoded):
pass pass
@ -627,11 +626,11 @@ class CryptPasswordHasher(BasePasswordHasher):
def safe_summary(self, encoded): def safe_summary(self, encoded):
algorithm, salt, data = encoded.split('$', 2) algorithm, salt, data = encoded.split('$', 2)
assert algorithm == self.algorithm assert algorithm == self.algorithm
return OrderedDict([ return {
(_('algorithm'), algorithm), _('algorithm'): algorithm,
(_('salt'), salt), _('salt'): salt,
(_('hash'), mask_hash(data, show=3)), _('hash'): mask_hash(data, show=3),
]) }
def harden_runtime(self, password, encoded): def harden_runtime(self, password, encoded):
pass pass

View File

@ -1,6 +1,5 @@
import functools import functools
import os import os
from collections import OrderedDict
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
@ -54,7 +53,7 @@ class FileSystemFinder(BaseFinder):
# List of locations with static files # List of locations with static files
self.locations = [] self.locations = []
# Maps dir paths to an appropriate storage instance # Maps dir paths to an appropriate storage instance
self.storages = OrderedDict() self.storages = {}
for root in settings.STATICFILES_DIRS: for root in settings.STATICFILES_DIRS:
if isinstance(root, (list, tuple)): if isinstance(root, (list, tuple)):
prefix, root = root prefix, root = root
@ -144,7 +143,7 @@ class AppDirectoriesFinder(BaseFinder):
# The list of apps that are handled # The list of apps that are handled
self.apps = [] self.apps = []
# Mapping of app names to storage instances # Mapping of app names to storage instances
self.storages = OrderedDict() self.storages = {}
app_configs = apps.get_app_configs() app_configs = apps.get_app_configs()
if app_names: if app_names:
app_names = set(app_names) app_names = set(app_names)

View File

@ -1,5 +1,4 @@
import os import os
from collections import OrderedDict
from django.apps import apps from django.apps import apps
from django.contrib.staticfiles.finders import get_finders from django.contrib.staticfiles.finders import get_finders
@ -100,7 +99,7 @@ class Command(BaseCommand):
else: else:
handler = self.copy_file handler = self.copy_file
found_files = OrderedDict() found_files = {}
for finder in get_finders(): for finder in get_finders():
for path, storage in finder.list(self.ignore_patterns): for path, storage in finder.list(self.ignore_patterns):
# Prefix the relative path if the source storage contains it # Prefix the relative path if the source storage contains it

View File

@ -4,7 +4,6 @@ import os
import posixpath import posixpath
import re import re
import warnings import warnings
from collections import OrderedDict
from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit
from django.conf import settings from django.conf import settings
@ -59,7 +58,7 @@ class HashedFilesMixin:
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._patterns = OrderedDict() self._patterns = {}
self.hashed_files = {} self.hashed_files = {}
for extension, patterns in self.patterns: for extension, patterns in self.patterns:
for pattern in patterns: for pattern in patterns:
@ -208,7 +207,7 @@ class HashedFilesMixin:
def post_process(self, paths, dry_run=False, **options): def post_process(self, paths, dry_run=False, **options):
""" """
Post process the given OrderedDict of files (called from collectstatic). Post process the given dictionary of files (called from collectstatic).
Processing is actually two separate operations: Processing is actually two separate operations:
@ -225,7 +224,7 @@ class HashedFilesMixin:
return return
# where to store the new paths # where to store the new paths
hashed_files = OrderedDict() hashed_files = {}
# build a list of adjustable files # build a list of adjustable files
adjustable_paths = [ adjustable_paths = [
@ -386,20 +385,20 @@ class ManifestFilesMixin(HashedFilesMixin):
def load_manifest(self): def load_manifest(self):
content = self.read_manifest() content = self.read_manifest()
if content is None: if content is None:
return OrderedDict() return {}
try: try:
stored = json.loads(content, object_pairs_hook=OrderedDict) stored = json.loads(content)
except json.JSONDecodeError: except json.JSONDecodeError:
pass pass
else: else:
version = stored.get('version') version = stored.get('version')
if version == '1.0': if version == '1.0':
return stored.get('paths', OrderedDict()) return stored.get('paths', {})
raise ValueError("Couldn't load manifest '%s' (version %s)" % raise ValueError("Couldn't load manifest '%s' (version %s)" %
(self.manifest_name, self.manifest_version)) (self.manifest_name, self.manifest_version))
def post_process(self, *args, **kwargs): def post_process(self, *args, **kwargs):
self.hashed_files = OrderedDict() self.hashed_files = {}
yield from super().post_process(*args, **kwargs) yield from super().post_process(*args, **kwargs)
self.save_manifest() self.save_manifest()

View File

@ -2,7 +2,7 @@ import functools
import os import os
import pkgutil import pkgutil
import sys import sys
from collections import OrderedDict, defaultdict from collections import defaultdict
from difflib import get_close_matches from difflib import get_close_matches
from importlib import import_module from importlib import import_module
@ -339,8 +339,8 @@ class ManagementUtility:
# The exception will be raised later in the child process # The exception will be raised later in the child process
# started by the autoreloader. Pretend it didn't happen by # started by the autoreloader. Pretend it didn't happen by
# loading an empty list of applications. # loading an empty list of applications.
apps.all_models = defaultdict(OrderedDict) apps.all_models = defaultdict(dict)
apps.app_configs = OrderedDict() apps.app_configs = {}
apps.apps_ready = apps.models_ready = apps.ready = True apps.apps_ready = apps.models_ready = apps.ready = True
# Remove options not compatible with the built-in runserver # Remove options not compatible with the built-in runserver

View File

@ -1,5 +1,4 @@
import warnings import warnings
from collections import OrderedDict
from django.apps import apps from django.apps import apps
from django.core import serializers from django.core import serializers
@ -87,14 +86,14 @@ class Command(BaseCommand):
if not app_labels: if not app_labels:
if primary_keys: if primary_keys:
raise CommandError("You can only use --pks option with one model") raise CommandError("You can only use --pks option with one model")
app_list = OrderedDict.fromkeys( app_list = dict.fromkeys(
app_config for app_config in apps.get_app_configs() app_config for app_config in apps.get_app_configs()
if app_config.models_module is not None and app_config not in excluded_apps if app_config.models_module is not None and app_config not in excluded_apps
) )
else: else:
if len(app_labels) > 1 and primary_keys: if len(app_labels) > 1 and primary_keys:
raise CommandError("You can only use --pks option with one model") raise CommandError("You can only use --pks option with one model")
app_list = OrderedDict() app_list = {}
for label in app_labels: for label in app_labels:
try: try:
app_label, model_label = label.split('.') app_label, model_label = label.split('.')

View File

@ -1,6 +1,5 @@
import keyword import keyword
import re import re
from collections import OrderedDict
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.db import DEFAULT_DB_ALIAS, connections from django.db import DEFAULT_DB_ALIAS, connections
@ -98,7 +97,7 @@ class Command(BaseCommand):
column_to_field_name = {} # Maps column names to names of model fields column_to_field_name = {} # Maps column names to names of model fields
for row in table_description: for row in table_description:
comment_notes = [] # Holds Field notes, to be displayed in a Python comment. comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
extra_params = OrderedDict() # Holds Field parameters such as 'db_column'. extra_params = {} # Holds Field parameters such as 'db_column'.
column_name = row.name column_name = row.name
is_relation = column_name in relations is_relation = column_name in relations
@ -232,7 +231,7 @@ class Command(BaseCommand):
description, this routine will return the given field type name, as description, this routine will return the given field type name, as
well as any additional keyword parameters and notes for the field. well as any additional keyword parameters and notes for the field.
""" """
field_params = OrderedDict() field_params = {}
field_notes = [] field_notes = []
try: try:

View File

@ -1,5 +1,4 @@
import time import time
from collections import OrderedDict
from importlib import import_module from importlib import import_module
from django.apps import apps from django.apps import apps
@ -314,10 +313,10 @@ class Command(BaseCommand):
(opts.auto_created and converter(opts.auto_created._meta.db_table) in tables) (opts.auto_created and converter(opts.auto_created._meta.db_table) in tables)
) )
manifest = OrderedDict( manifest = {
(app_name, list(filter(model_installed, model_list))) app_name: list(filter(model_installed, model_list))
for app_name, model_list in all_models for app_name, model_list in all_models
) }
# Create the tables for each model # Create the tables for each model
if self.verbosity >= 1: if self.verbosity >= 1:

View File

@ -3,7 +3,6 @@ A Python "serializer". Doesn't do much serializing per se -- just converts to
and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for
other serializers. other serializers.
""" """
from collections import OrderedDict
from django.apps import apps from django.apps import apps
from django.core.serializers import base from django.core.serializers import base
@ -26,14 +25,14 @@ class Serializer(base.Serializer):
pass pass
def start_object(self, obj): def start_object(self, obj):
self._current = OrderedDict() self._current = {}
def end_object(self, obj): def end_object(self, obj):
self.objects.append(self.get_dump_object(obj)) self.objects.append(self.get_dump_object(obj))
self._current = None self._current = None
def get_dump_object(self, obj): def get_dump_object(self, obj):
data = OrderedDict([('model', str(obj._meta))]) data = {'model': str(obj._meta)}
if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'): if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'):
data["pk"] = self._value_from_field(obj, obj._meta.pk) data["pk"] = self._value_from_field(obj, obj._meta.pk)
data['fields'] = self._current data['fields'] = self._current

View File

@ -34,6 +34,9 @@ class DjangoSafeDumper(SafeDumper):
DjangoSafeDumper.add_representer(decimal.Decimal, DjangoSafeDumper.represent_decimal) DjangoSafeDumper.add_representer(decimal.Decimal, DjangoSafeDumper.represent_decimal)
DjangoSafeDumper.add_representer(collections.OrderedDict, DjangoSafeDumper.represent_ordered_dict) DjangoSafeDumper.add_representer(collections.OrderedDict, DjangoSafeDumper.represent_ordered_dict)
# Workaround to represent dictionaries in insertion order.
# See https://github.com/yaml/pyyaml/pull/143.
DjangoSafeDumper.add_representer(dict, DjangoSafeDumper.represent_ordered_dict)
class Serializer(PythonSerializer): class Serializer(PythonSerializer):

View File

@ -8,7 +8,6 @@ import math
import re import re
import types import types
import uuid import uuid
from collections import OrderedDict
from django.conf import SettingsReference from django.conf import SettingsReference
from django.db import models from django.db import models
@ -273,25 +272,26 @@ class UUIDSerializer(BaseSerializer):
class Serializer: class Serializer:
_registry = OrderedDict([ _registry = {
(frozenset, FrozensetSerializer), # Some of these are order-dependent.
(list, SequenceSerializer), frozenset: FrozensetSerializer,
(set, SetSerializer), list: SequenceSerializer,
(tuple, TupleSerializer), set: SetSerializer,
(dict, DictionarySerializer), tuple: TupleSerializer,
(enum.Enum, EnumSerializer), dict: DictionarySerializer,
(datetime.datetime, DatetimeDatetimeSerializer), enum.Enum: EnumSerializer,
((datetime.date, datetime.timedelta, datetime.time), DateTimeSerializer), datetime.datetime: DatetimeDatetimeSerializer,
(SettingsReference, SettingsReferenceSerializer), (datetime.date, datetime.timedelta, datetime.time): DateTimeSerializer,
(float, FloatSerializer), SettingsReference: SettingsReferenceSerializer,
((bool, int, type(None), bytes, str), BaseSimpleSerializer), float: FloatSerializer,
(decimal.Decimal, DecimalSerializer), (bool, int, type(None), bytes, str): BaseSimpleSerializer,
((functools.partial, functools.partialmethod), FunctoolsPartialSerializer), decimal.Decimal: DecimalSerializer,
((types.FunctionType, types.BuiltinFunctionType, types.MethodType), FunctionTypeSerializer), (functools.partial, functools.partialmethod): FunctoolsPartialSerializer,
(collections.abc.Iterable, IterableSerializer), (types.FunctionType, types.BuiltinFunctionType, types.MethodType): FunctionTypeSerializer,
((COMPILED_REGEX_TYPE, RegexObject), RegexSerializer), collections.abc.Iterable: IterableSerializer,
(uuid.UUID, UUIDSerializer), (COMPILED_REGEX_TYPE, RegexObject): RegexSerializer,
]) uuid.UUID: UUIDSerializer,
}
@classmethod @classmethod
def register(cls, type_, serializer): def register(cls, type_, serializer):

View File

@ -1,5 +1,4 @@
import copy import copy
from collections import OrderedDict
from contextlib import contextmanager from contextlib import contextmanager
from django.apps import AppConfig from django.apps import AppConfig
@ -334,7 +333,7 @@ class StateApps(Apps):
if app_label not in self.app_configs: if app_label not in self.app_configs:
self.app_configs[app_label] = AppConfigStub(app_label) self.app_configs[app_label] = AppConfigStub(app_label)
self.app_configs[app_label].apps = self self.app_configs[app_label].apps = self
self.app_configs[app_label].models = OrderedDict() self.app_configs[app_label].models = {}
self.app_configs[app_label].models[model._meta.model_name] = model self.app_configs[app_label].models[model._meta.model_name] = model
self.do_pending_operations(model) self.do_pending_operations(model)
self.clear_cache() self.clear_cache()

View File

@ -1,4 +1,4 @@
from collections import Counter, OrderedDict from collections import Counter
from operator import attrgetter from operator import attrgetter
from django.db import IntegrityError, connections, transaction from django.db import IntegrityError, connections, transaction
@ -64,7 +64,7 @@ class Collector:
def __init__(self, using): def __init__(self, using):
self.using = using self.using = using
# Initially, {model: {instances}}, later values become lists. # Initially, {model: {instances}}, later values become lists.
self.data = OrderedDict() self.data = {}
self.field_updates = {} # {model: {(field, value): {instances}}} self.field_updates = {} # {model: {(field, value): {instances}}}
# fast_deletes is a list of queryset-likes that can be deleted without # fast_deletes is a list of queryset-likes that can be deleted without
# fetching the objects into memory. # fetching the objects into memory.
@ -257,8 +257,7 @@ class Collector:
found = True found = True
if not found: if not found:
return return
self.data = OrderedDict((model, self.data[model]) self.data = {model: self.data[model] for model in sorted_models}
for model in sorted_models)
def delete(self): def delete(self):
# sort instance collections # sort instance collections

View File

@ -1,7 +1,7 @@
import copy import copy
import inspect import inspect
from bisect import bisect from bisect import bisect
from collections import OrderedDict, defaultdict from collections import defaultdict
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
@ -117,7 +117,7 @@ class Options:
# concrete models, the concrete_model is always the class itself. # concrete models, the concrete_model is always the class itself.
self.concrete_model = None self.concrete_model = None
self.swappable = None self.swappable = None
self.parents = OrderedDict() self.parents = {}
self.auto_created = False self.auto_created = False
# List of all lookups defined in ForeignKey 'limit_choices_to' options # List of all lookups defined in ForeignKey 'limit_choices_to' options

View File

@ -5,7 +5,7 @@ The main QuerySet implementation. This provides the public API for the ORM.
import copy import copy
import operator import operator
import warnings import warnings
from collections import OrderedDict, namedtuple from collections import namedtuple
from functools import lru_cache from functools import lru_cache
from itertools import chain from itertools import chain
@ -725,7 +725,7 @@ class QuerySet:
query = self.query.chain(sql.UpdateQuery) query = self.query.chain(sql.UpdateQuery)
query.add_update_values(kwargs) query.add_update_values(kwargs)
# Clear any annotations so that they won't be present in subqueries. # Clear any annotations so that they won't be present in subqueries.
query._annotations = None query.annotations = {}
with transaction.mark_for_rollback_on_error(using=self.db): with transaction.mark_for_rollback_on_error(using=self.db):
rows = query.get_compiler(self.db).execute_sql(CURSOR) rows = query.get_compiler(self.db).execute_sql(CURSOR)
self._result_cache = None self._result_cache = None
@ -744,7 +744,7 @@ class QuerySet:
query = self.query.chain(sql.UpdateQuery) query = self.query.chain(sql.UpdateQuery)
query.add_update_fields(values) query.add_update_fields(values)
# Clear any annotations so that they won't be present in subqueries. # Clear any annotations so that they won't be present in subqueries.
query._annotations = None query.annotations = {}
self._result_cache = None self._result_cache = None
return query.get_compiler(self.db).execute_sql(CURSOR) return query.get_compiler(self.db).execute_sql(CURSOR)
_update.alters_data = True _update.alters_data = True
@ -1014,7 +1014,7 @@ class QuerySet:
with extra data or aggregations. with extra data or aggregations.
""" """
self._validate_values_are_expressions(args + tuple(kwargs.values()), method_name='annotate') self._validate_values_are_expressions(args + tuple(kwargs.values()), method_name='annotate')
annotations = OrderedDict() # To preserve ordering of args annotations = {}
for arg in args: for arg in args:
# The default_alias property may raise a TypeError. # The default_alias property may raise a TypeError.
try: try:

View File

@ -317,7 +317,7 @@ class SQLCompiler:
), False)) ), False))
continue continue
if not self.query._extra or col not in self.query._extra: if not self.query.extra or col not in self.query.extra:
# 'col' is of the form 'field' or 'field1__field2' or # 'col' is of the form 'field' or 'field1__field2' or
# '-field1__field2__field', etc. # '-field1__field2__field', etc.
order_by.extend(self.find_ordering_name( order_by.extend(self.find_ordering_name(
@ -1438,7 +1438,7 @@ class SQLUpdateCompiler(SQLCompiler):
query = self.query.chain(klass=Query) query = self.query.chain(klass=Query)
query.select_related = False query.select_related = False
query.clear_ordering(True) query.clear_ordering(True)
query._extra = {} query.extra = {}
query.select = [] query.select = []
query.add_fields([query.get_meta().pk.name]) query.add_fields([query.get_meta().pk.name])
super().pre_sql_setup() super().pre_sql_setup()

View File

@ -8,7 +8,7 @@ all about the internals of models in order to get the information it needs.
""" """
import difflib import difflib
import functools import functools
from collections import Counter, OrderedDict, namedtuple from collections import Counter, namedtuple
from collections.abc import Iterator, Mapping from collections.abc import Iterator, Mapping
from itertools import chain, count, product from itertools import chain, count, product
from string import ascii_uppercase from string import ascii_uppercase
@ -152,7 +152,7 @@ class Query:
# types they are. The key is the alias of the joined table (possibly # types they are. The key is the alias of the joined table (possibly
# the table name) and the value is a Join-like object (see # the table name) and the value is a Join-like object (see
# sql.datastructures.Join for more information). # sql.datastructures.Join for more information).
self.alias_map = OrderedDict() self.alias_map = {}
# Sometimes the query contains references to aliases in outer queries (as # Sometimes the query contains references to aliases in outer queries (as
# a result of split_exclude). Correct alias quoting needs to know these # a result of split_exclude). Correct alias quoting needs to know these
# aliases too. # aliases too.
@ -199,10 +199,7 @@ class Query:
self.values_select = () self.values_select = ()
# SQL annotation-related attributes # SQL annotation-related attributes
# The _annotations will be an OrderedDict when used. Due to the cost self.annotations = {} # Maps alias -> Annotation Expression
# of creating OrderedDict this attribute is created lazily (in
# self.annotations property).
self._annotations = None # Maps alias -> Annotation Expression
self.annotation_select_mask = None self.annotation_select_mask = None
self._annotation_select_cache = None self._annotation_select_cache = None
@ -213,9 +210,7 @@ class Query:
# These are for extensions. The contents are more or less appended # These are for extensions. The contents are more or less appended
# verbatim to the appropriate clause. # verbatim to the appropriate clause.
# The _extra attribute is an OrderedDict, lazily created similarly to self.extra = {} # Maps col_alias -> (col_sql, params).
# .annotations
self._extra = None # Maps col_alias -> (col_sql, params).
self.extra_select_mask = None self.extra_select_mask = None
self._extra_select_cache = None self._extra_select_cache = None
@ -233,18 +228,6 @@ class Query:
self.explain_format = None self.explain_format = None
self.explain_options = {} self.explain_options = {}
@property
def extra(self):
if self._extra is None:
self._extra = OrderedDict()
return self._extra
@property
def annotations(self):
if self._annotations is None:
self._annotations = OrderedDict()
return self._annotations
@property @property
def has_select_fields(self): def has_select_fields(self):
return bool(self.select or self.annotation_select_mask or self.extra_select_mask) return bool(self.select or self.annotation_select_mask or self.extra_select_mask)
@ -311,7 +294,7 @@ class Query:
obj.external_aliases = self.external_aliases.copy() obj.external_aliases = self.external_aliases.copy()
obj.table_map = self.table_map.copy() obj.table_map = self.table_map.copy()
obj.where = self.where.clone() obj.where = self.where.clone()
obj._annotations = self._annotations.copy() if self._annotations is not None else None obj.annotations = self.annotations.copy()
if self.annotation_select_mask is None: if self.annotation_select_mask is None:
obj.annotation_select_mask = None obj.annotation_select_mask = None
else: else:
@ -322,7 +305,7 @@ class Query:
# It will get re-populated in the cloned queryset the next time it's # It will get re-populated in the cloned queryset the next time it's
# used. # used.
obj._annotation_select_cache = None obj._annotation_select_cache = None
obj._extra = self._extra.copy() if self._extra is not None else None obj.extra = self.extra.copy()
if self.extra_select_mask is None: if self.extra_select_mask is None:
obj.extra_select_mask = None obj.extra_select_mask = None
else: else:
@ -479,7 +462,7 @@ class Query:
outer_query = self outer_query = self
self.select = () self.select = ()
self.default_cols = False self.default_cols = False
self._extra = {} self.extra = {}
outer_query.clear_ordering(True) outer_query.clear_ordering(True)
outer_query.clear_limits() outer_query.clear_limits()
@ -613,7 +596,7 @@ class Query:
# It would be nice to be able to handle this, but the queries don't # It would be nice to be able to handle this, but the queries don't
# really make sense (or return consistent value sets). Not worth # really make sense (or return consistent value sets). Not worth
# the extra complexity when you can write a real query instead. # the extra complexity when you can write a real query instead.
if self._extra and rhs._extra: if self.extra and rhs.extra:
raise ValueError("When merging querysets using 'or', you cannot have extra(select=…) on both sides.") raise ValueError("When merging querysets using 'or', you cannot have extra(select=…) on both sides.")
self.extra.update(rhs.extra) self.extra.update(rhs.extra)
extra_select_mask = set() extra_select_mask = set()
@ -825,9 +808,9 @@ class Query:
if isinstance(self.group_by, tuple): if isinstance(self.group_by, tuple):
self.group_by = tuple([col.relabeled_clone(change_map) for col in self.group_by]) self.group_by = tuple([col.relabeled_clone(change_map) for col in self.group_by])
self.select = tuple([col.relabeled_clone(change_map) for col in self.select]) self.select = tuple([col.relabeled_clone(change_map) for col in self.select])
self._annotations = self._annotations and OrderedDict( self.annotations = self.annotations and {
(key, col.relabeled_clone(change_map)) for key, col in self._annotations.items() key: col.relabeled_clone(change_map) for key, col in self.annotations.items()
) }
# 2. Rename the alias in the internal table/alias datastructures. # 2. Rename the alias in the internal table/alias datastructures.
for old_alias, new_alias in change_map.items(): for old_alias, new_alias in change_map.items():
@ -887,11 +870,10 @@ class Query:
) )
self.subq_aliases = self.subq_aliases.union([self.alias_prefix]) self.subq_aliases = self.subq_aliases.union([self.alias_prefix])
outer_query.subq_aliases = outer_query.subq_aliases.union(self.subq_aliases) outer_query.subq_aliases = outer_query.subq_aliases.union(self.subq_aliases)
change_map = OrderedDict() self.change_aliases({
for pos, alias in enumerate(self.alias_map): alias: '%s%d' % (self.alias_prefix, pos)
new_alias = '%s%d' % (self.alias_prefix, pos) for pos, alias in enumerate(self.alias_map)
change_map[alias] = new_alias })
self.change_aliases(change_map)
def get_initial_alias(self): def get_initial_alias(self):
""" """
@ -1042,7 +1024,7 @@ class Query:
Solve the lookup type from the lookup (e.g.: 'foobar__id__icontains'). Solve the lookup type from the lookup (e.g.: 'foobar__id__icontains').
""" """
lookup_splitted = lookup.split(LOOKUP_SEP) lookup_splitted = lookup.split(LOOKUP_SEP)
if self._annotations: if self.annotations:
expression, expression_lookups = refs_expression(lookup_splitted, self.annotations) expression, expression_lookups = refs_expression(lookup_splitted, self.annotations)
if expression: if expression:
return expression_lookups, (), expression return expression_lookups, (), expression
@ -1867,7 +1849,7 @@ class Query:
# dictionary with their parameters in 'select_params' so that # dictionary with their parameters in 'select_params' so that
# subsequent updates to the select dictionary also adjust the # subsequent updates to the select dictionary also adjust the
# parameters appropriately. # parameters appropriately.
select_pairs = OrderedDict() select_pairs = {}
if select_params: if select_params:
param_iter = iter(select_params) param_iter = iter(select_params)
else: else:
@ -1881,7 +1863,6 @@ class Query:
entry_params.append(next(param_iter)) entry_params.append(next(param_iter))
pos = entry.find("%s", pos + 2) pos = entry.find("%s", pos + 2)
select_pairs[name] = (entry, entry_params) select_pairs[name] = (entry, entry_params)
# This is order preserving, since self.extra_select is an OrderedDict.
self.extra.update(select_pairs) self.extra.update(select_pairs)
if where or params: if where or params:
self.where.add(ExtraWhere(where, params), AND) self.where.add(ExtraWhere(where, params), AND)
@ -1998,7 +1979,7 @@ class Query:
field_names = [] field_names = []
extra_names = [] extra_names = []
annotation_names = [] annotation_names = []
if not self._extra and not self._annotations: if not self.extra and not self.annotations:
# Shortcut - if there are no extra or annotations, then # Shortcut - if there are no extra or annotations, then
# the values() clause must be just field names. # the values() clause must be just field names.
field_names = list(fields) field_names = list(fields)
@ -2022,18 +2003,18 @@ class Query:
@property @property
def annotation_select(self): def annotation_select(self):
""" """
Return the OrderedDict of aggregate columns that are not masked and Return the dictionary of aggregate columns that are not masked and
should be used in the SELECT clause. Cache this result for performance. should be used in the SELECT clause. Cache this result for performance.
""" """
if self._annotation_select_cache is not None: if self._annotation_select_cache is not None:
return self._annotation_select_cache return self._annotation_select_cache
elif not self._annotations: elif not self.annotations:
return {} return {}
elif self.annotation_select_mask is not None: elif self.annotation_select_mask is not None:
self._annotation_select_cache = OrderedDict( self._annotation_select_cache = {
(k, v) for k, v in self.annotations.items() k: v for k, v in self.annotations.items()
if k in self.annotation_select_mask if k in self.annotation_select_mask
) }
return self._annotation_select_cache return self._annotation_select_cache
else: else:
return self.annotations return self.annotations
@ -2042,13 +2023,13 @@ class Query:
def extra_select(self): def extra_select(self):
if self._extra_select_cache is not None: if self._extra_select_cache is not None:
return self._extra_select_cache return self._extra_select_cache
if not self._extra: if not self.extra:
return {} return {}
elif self.extra_select_mask is not None: elif self.extra_select_mask is not None:
self._extra_select_cache = OrderedDict( self._extra_select_cache = {
(k, v) for k, v in self.extra.items() k: v for k, v in self.extra.items()
if k in self.extra_select_mask if k in self.extra_select_mask
) }
return self._extra_select_cache return self._extra_select_cache
else: else:
return self.extra return self.extra

View File

@ -3,7 +3,6 @@ Form classes
""" """
import copy import copy
from collections import OrderedDict
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
# BoundField is imported for backwards compatibility in Django 1.9 # BoundField is imported for backwards compatibility in Django 1.9
@ -31,12 +30,12 @@ class DeclarativeFieldsMetaclass(MediaDefiningClass):
if isinstance(value, Field): if isinstance(value, Field):
current_fields.append((key, value)) current_fields.append((key, value))
attrs.pop(key) attrs.pop(key)
attrs['declared_fields'] = OrderedDict(current_fields) attrs['declared_fields'] = dict(current_fields)
new_class = super(DeclarativeFieldsMetaclass, mcs).__new__(mcs, name, bases, attrs) new_class = super(DeclarativeFieldsMetaclass, mcs).__new__(mcs, name, bases, attrs)
# Walk through the MRO. # Walk through the MRO.
declared_fields = OrderedDict() declared_fields = {}
for base in reversed(new_class.__mro__): for base in reversed(new_class.__mro__):
# Collect fields from base class. # Collect fields from base class.
if hasattr(base, 'declared_fields'): if hasattr(base, 'declared_fields'):
@ -52,11 +51,6 @@ class DeclarativeFieldsMetaclass(MediaDefiningClass):
return new_class return new_class
@classmethod
def __prepare__(metacls, name, bases, **kwds):
# Remember the order in which form fields are defined.
return OrderedDict()
@html_safe @html_safe
class BaseForm: class BaseForm:
@ -129,7 +123,7 @@ class BaseForm:
""" """
if field_order is None: if field_order is None:
return return
fields = OrderedDict() fields = {}
for key in field_order: for key in field_order:
try: try:
fields[key] = self.fields.pop(key) fields[key] = self.fields.pop(key)

View File

@ -3,7 +3,6 @@ Helper functions for creating Form classes from Django models
and database field objects. and database field objects.
""" """
from collections import OrderedDict
from itertools import chain from itertools import chain
from django.core.exceptions import ( from django.core.exceptions import (
@ -105,7 +104,7 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None,
labels=None, help_texts=None, error_messages=None, labels=None, help_texts=None, error_messages=None,
field_classes=None, *, apply_limit_choices_to=True): field_classes=None, *, apply_limit_choices_to=True):
""" """
Return an ``OrderedDict`` containing form fields for the given model. Return a dictionary containing form fields for the given model.
``fields`` is an optional list of field names. If provided, return only the ``fields`` is an optional list of field names. If provided, return only the
named fields. named fields.
@ -134,7 +133,7 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None,
``apply_limit_choices_to`` is a boolean indicating if limit_choices_to ``apply_limit_choices_to`` is a boolean indicating if limit_choices_to
should be applied to a field's queryset. should be applied to a field's queryset.
""" """
field_list = [] field_dict = {}
ignored = [] ignored = []
opts = model._meta opts = model._meta
# Avoid circular import # Avoid circular import
@ -178,15 +177,14 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None,
if formfield: if formfield:
if apply_limit_choices_to: if apply_limit_choices_to:
apply_limit_choices_to_to_formfield(formfield) apply_limit_choices_to_to_formfield(formfield)
field_list.append((f.name, formfield)) field_dict[f.name] = formfield
else: else:
ignored.append(f.name) ignored.append(f.name)
field_dict = OrderedDict(field_list)
if fields: if fields:
field_dict = OrderedDict( field_dict = {
[(f, field_dict.get(f)) for f in fields f: field_dict.get(f) for f in fields
if ((not exclude) or (exclude and f not in exclude)) and (f not in ignored)] if (not exclude or f not in exclude) and f not in ignored
) }
return field_dict return field_dict

View File

@ -1,5 +1,5 @@
import functools import functools
from collections import Counter, OrderedDict from collections import Counter
from pathlib import Path from pathlib import Path
from django.apps import apps from django.apps import apps
@ -27,7 +27,7 @@ class EngineHandler:
if self._templates is None: if self._templates is None:
self._templates = settings.TEMPLATES self._templates = settings.TEMPLATES
templates = OrderedDict() templates = {}
backend_names = [] backend_names = []
for tpl in self._templates: for tpl in self._templates:
try: try:

View File

@ -1,4 +1,3 @@
import collections
import logging import logging
import re import re
import sys import sys
@ -280,8 +279,7 @@ def get_unique_databases_and_mirrors(aliases=None):
if alias != DEFAULT_DB_ALIAS and connection.creation.test_db_signature() != default_sig: if alias != DEFAULT_DB_ALIAS and connection.creation.test_db_signature() != default_sig:
dependencies[alias] = test_settings.get('DEPENDENCIES', [DEFAULT_DB_ALIAS]) dependencies[alias] = test_settings.get('DEPENDENCIES', [DEFAULT_DB_ALIAS])
test_databases = dependency_ordered(test_databases.items(), dependencies) test_databases = dict(dependency_ordered(test_databases.items(), dependencies))
test_databases = collections.OrderedDict(test_databases)
return test_databases, mirrored_aliases return test_databases, mirrored_aliases

View File

@ -1,16 +1,14 @@
import copy import copy
from collections import OrderedDict
from collections.abc import Mapping from collections.abc import Mapping
class OrderedSet: class OrderedSet:
""" """
A set which keeps the ordering of the inserted items. A set which keeps the ordering of the inserted items.
Currently backs onto OrderedDict.
""" """
def __init__(self, iterable=None): def __init__(self, iterable=None):
self.dict = OrderedDict.fromkeys(iterable or ()) self.dict = dict.fromkeys(iterable or ())
def add(self, item): def add(self, item):
self.dict[item] = None self.dict[item] = None

View File

@ -5,7 +5,6 @@ import os
import re import re
import sys import sys
import warnings import warnings
from collections import OrderedDict
from threading import local from threading import local
from django.apps import apps from django.apps import apps
@ -385,9 +384,9 @@ def check_for_language(lang_code):
@functools.lru_cache() @functools.lru_cache()
def get_languages(): def get_languages():
""" """
Cache of settings.LANGUAGES in an OrderedDict for easy lookups by key. Cache of settings.LANGUAGES in a dictionary for easy lookups by key.
""" """
return OrderedDict(settings.LANGUAGES) return dict(settings.LANGUAGES)
@functools.lru_cache(maxsize=1000) @functools.lru_cache(maxsize=1000)

View File

@ -3,7 +3,6 @@ Utilities for XML generation/parsing.
""" """
import re import re
from collections import OrderedDict
from xml.sax.saxutils import XMLGenerator from xml.sax.saxutils import XMLGenerator
@ -30,5 +29,5 @@ class SimplerXMLGenerator(XMLGenerator):
def startElement(self, name, attrs): def startElement(self, name, attrs):
# Sort attrs for a deterministic output. # Sort attrs for a deterministic output.
sorted_attrs = OrderedDict(sorted(attrs.items())) if attrs else attrs sorted_attrs = dict(sorted(attrs.items())) if attrs else attrs
super().startElement(name, sorted_attrs) super().startElement(name, sorted_attrs)

View File

@ -1363,17 +1363,14 @@ of the arguments is required, but you should use at least one of them.
In some rare cases, you might wish to pass parameters to the SQL In some rare cases, you might wish to pass parameters to the SQL
fragments in ``extra(select=...)``. For this purpose, use the fragments in ``extra(select=...)``. For this purpose, use the
``select_params`` parameter. Since ``select_params`` is a sequence and ``select_params`` parameter.
the ``select`` attribute is a dictionary, some care is required so that
the parameters are matched up correctly with the extra select pieces.
In this situation, you should use a :class:`collections.OrderedDict` for
the ``select`` value, not just a normal Python dictionary.
This will work, for example:: This will work, for example::
Blog.objects.extra( Blog.objects.extra(
select=OrderedDict([('a', '%s'), ('b', '%s')]), select={'a': '%s', 'b': '%s'},
select_params=('one', 'two')) select_params=('one', 'two'),
)
If you need to use a literal ``%s`` inside your select string, use If you need to use a literal ``%s`` inside your select string, use
the sequence ``%%s``. the sequence ``%%s``.

View File

@ -1,5 +1,4 @@
import datetime import datetime
from collections import OrderedDict
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase
@ -73,10 +72,7 @@ class ExtraRegressTests(TestCase):
# Extra select parameters should stay tied to their corresponding # Extra select parameters should stay tied to their corresponding
# select portions. Applies when portions are updated or otherwise # select portions. Applies when portions are updated or otherwise
# moved around. # moved around.
qs = User.objects.extra( qs = User.objects.extra(select={'alpha': '%s', 'beta': "2", 'gamma': '%s'}, select_params=(1, 3))
select=OrderedDict((("alpha", "%s"), ("beta", "2"), ("gamma", "%s"))),
select_params=(1, 3)
)
qs = qs.extra(select={"beta": 4}) qs = qs.extra(select={"beta": 4})
qs = qs.extra(select={"alpha": "%s"}, select_params=[5]) qs = qs.extra(select={"alpha": "%s"}, select_params=[5])
self.assertEqual( self.assertEqual(
@ -184,7 +180,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values() .values()
), ),
[{ [{
@ -198,7 +194,7 @@ class ExtraRegressTests(TestCase):
list( list(
TestObject.objects TestObject.objects
.values() .values()
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
), ),
[{ [{
'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first', 'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first',
@ -210,7 +206,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values('first', 'second') .values('first', 'second')
), ),
[{'second': 'second', 'first': 'first'}] [{'second': 'second', 'first': 'first'}]
@ -221,7 +217,7 @@ class ExtraRegressTests(TestCase):
list( list(
TestObject.objects TestObject.objects
.values('first', 'second') .values('first', 'second')
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
), ),
[{'second': 'second', 'first': 'first'}] [{'second': 'second', 'first': 'first'}]
) )
@ -230,7 +226,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values('first', 'second', 'foo') .values('first', 'second', 'foo')
), ),
[{'second': 'second', 'foo': 'first', 'first': 'first'}] [{'second': 'second', 'foo': 'first', 'first': 'first'}]
@ -240,7 +236,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values('foo', 'whiz') .values('foo', 'whiz')
), ),
[{'foo': 'first', 'whiz': 'third'}] [{'foo': 'first', 'whiz': 'third'}]
@ -251,7 +247,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list() .values_list()
), ),
[('first', 'second', 'third', obj.pk, 'first', 'second', 'third')] [('first', 'second', 'third', obj.pk, 'first', 'second', 'third')]
@ -262,7 +258,7 @@ class ExtraRegressTests(TestCase):
list( list(
TestObject.objects TestObject.objects
.values_list() .values_list()
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
), ),
[('first', 'second', 'third', obj.pk, 'first', 'second', 'third')] [('first', 'second', 'third', obj.pk, 'first', 'second', 'third')]
) )
@ -271,7 +267,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list('first', 'second') .values_list('first', 'second')
), ),
[('first', 'second')] [('first', 'second')]
@ -282,7 +278,7 @@ class ExtraRegressTests(TestCase):
list( list(
TestObject.objects TestObject.objects
.values_list('first', 'second') .values_list('first', 'second')
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
), ),
[('first', 'second')] [('first', 'second')]
) )
@ -290,7 +286,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list('second', flat=True) .values_list('second', flat=True)
), ),
['second'] ['second']
@ -300,7 +296,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list('first', 'second', 'whiz') .values_list('first', 'second', 'whiz')
), ),
[('first', 'second', 'third')] [('first', 'second', 'third')]
@ -310,7 +306,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list('foo', 'whiz') .values_list('foo', 'whiz')
), ),
[('first', 'third')] [('first', 'third')]
@ -319,7 +315,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list('whiz', flat=True) .values_list('whiz', flat=True)
), ),
['third'] ['third']
@ -329,7 +325,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list('whiz', 'foo') .values_list('whiz', 'foo')
), ),
[('third', 'first')] [('third', 'first')]
@ -338,7 +334,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list('first', 'id') .values_list('first', 'id')
), ),
[('first', obj.pk)] [('first', obj.pk)]
@ -347,7 +343,7 @@ class ExtraRegressTests(TestCase):
self.assertEqual( self.assertEqual(
list( list(
TestObject.objects TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))) .extra(select={'foo': 'first', 'bar': 'second', 'whiz': 'third'})
.values_list('whiz', 'first', 'bar', 'id') .values_list('whiz', 'first', 'bar', 'id')
), ),
[('third', 'first', 'second', obj.pk)] [('third', 'first', 'second', obj.pk)]

View File

@ -1,7 +1,6 @@
import datetime import datetime
import pickle import pickle
import unittest import unittest
from collections import OrderedDict
from operator import attrgetter from operator import attrgetter
from django.core.exceptions import EmptyResultSet, FieldError from django.core.exceptions import EmptyResultSet, FieldError
@ -543,31 +542,6 @@ class Queries1Tests(TestCase):
# ...or use the field name. # ...or use the field name.
self.assertSequenceEqual(ExtraInfo.objects.values('note'), [{'note': 1}, {'note': 2}]) self.assertSequenceEqual(ExtraInfo.objects.values('note'), [{'note': 1}, {'note': 2}])
def test_ticket2902(self):
# Parameters can be given to extra_select, *if* you use an OrderedDict.
# (First we need to know which order the keys fall in "naturally" on
# your system, so we can put things in the wrong way around from
# normal. A normal dict would thus fail.)
s = [('a', '%s'), ('b', '%s')]
params = ['one', 'two']
if list({'a': 1, 'b': 2}) == ['a', 'b']:
s.reverse()
params.reverse()
d = Item.objects.extra(select=OrderedDict(s), select_params=params).values('a', 'b')[0]
self.assertEqual(d, {'a': 'one', 'b': 'two'})
# Order by the number of tags attached to an item.
qs = (
Item.objects
.extra(select={
'count': 'select count(*) from queries_item_tags where queries_item_tags.item_id = queries_item.id'
})
.order_by('-count')
)
self.assertEqual([o.count for o in qs], [2, 2, 1, 0])
def test_ticket6154(self): def test_ticket6154(self):
# Multiple filter statements are joined using "AND" all the time. # Multiple filter statements are joined using "AND" all the time.
@ -2249,9 +2223,7 @@ class ValuesQuerysetTests(TestCase):
def test_extra_values(self): def test_extra_values(self):
# testing for ticket 14930 issues # testing for ticket 14930 issues
qs = Number.objects.extra(select=OrderedDict([('value_plus_x', 'num+%s'), qs = Number.objects.extra(select={'value_plus_x': 'num+%s', 'value_minus_x': 'num-%s'}, select_params=(1, 2))
('value_minus_x', 'num-%s')]),
select_params=(1, 2))
qs = qs.order_by('value_minus_x') qs = qs.order_by('value_minus_x')
qs = qs.values('num') qs = qs.values('num')
self.assertSequenceEqual(qs, [{'num': 72}]) self.assertSequenceEqual(qs, [{'num': 72}])
@ -2295,9 +2267,7 @@ class ValuesQuerysetTests(TestCase):
def test_extra_multiple_select_params_values_order_by(self): def test_extra_multiple_select_params_values_order_by(self):
# testing for 23259 issue # testing for 23259 issue
qs = Number.objects.extra(select=OrderedDict([('value_plus_x', 'num+%s'), qs = Number.objects.extra(select={'value_plus_x': 'num+%s', 'value_minus_x': 'num-%s'}, select_params=(72, 72))
('value_minus_x', 'num-%s')]),
select_params=(72, 72))
qs = qs.order_by('value_minus_x') qs = qs.order_by('value_minus_x')
qs = qs.filter(num=1) qs = qs.filter(num=1)
qs = qs.values('num') qs = qs.values('num')

View File

@ -1,4 +1,3 @@
from collections import OrderedDict
from datetime import date, datetime from datetime import date, datetime
from django.conf.urls.i18n import i18n_patterns from django.conf.urls.i18n import i18n_patterns
@ -102,27 +101,27 @@ fixed_lastmod__mixed_sitemaps = {
'fixed-lastmod-mixed': FixedLastmodMixedSitemap, 'fixed-lastmod-mixed': FixedLastmodMixedSitemap,
} }
sitemaps_lastmod_mixed_ascending = OrderedDict([ sitemaps_lastmod_mixed_ascending = {
('no-lastmod', EmptySitemap), 'no-lastmod': EmptySitemap,
('lastmod', FixedLastmodSitemap), 'lastmod': FixedLastmodSitemap,
]) }
sitemaps_lastmod_mixed_descending = OrderedDict([ sitemaps_lastmod_mixed_descending = {
('lastmod', FixedLastmodSitemap), 'lastmod': FixedLastmodSitemap,
('no-lastmod', EmptySitemap), 'no-lastmod': EmptySitemap,
]) }
sitemaps_lastmod_ascending = OrderedDict([ sitemaps_lastmod_ascending = {
('date', DateSiteMap), 'date': DateSiteMap,
('datetime', FixedLastmodSitemap), 'datetime': FixedLastmodSitemap,
('datetime-newer', FixedNewerLastmodSitemap), 'datetime-newer': FixedNewerLastmodSitemap,
]) }
sitemaps_lastmod_descending = OrderedDict([ sitemaps_lastmod_descending = {
('datetime-newer', FixedNewerLastmodSitemap), 'datetime-newer': FixedNewerLastmodSitemap,
('datetime', FixedLastmodSitemap), 'datetime': FixedLastmodSitemap,
('date', DateSiteMap), 'date': DateSiteMap,
]) }
generic_sitemaps = { generic_sitemaps = {
'generic': GenericSitemap({'queryset': TestModel.objects.order_by('pk').all()}), 'generic': GenericSitemap({'queryset': TestModel.objects.order_by('pk').all()}),