diff options
| author | Andrew Godwin <andrew@aeracode.org> | 2012-08-10 12:40:37 +0100 |
|---|---|---|
| committer | Andrew Godwin <andrew@aeracode.org> | 2012-08-10 12:40:37 +0100 |
| commit | 184cf9ab798d5b25d855649ddb2ca580949778df (patch) | |
| tree | 8512633ec04a6979b0953e32e73c9a43d09e5805 /django/db | |
| parent | c4b2a3262cc79383d6562cfc7e9af20135c8e0bf (diff) | |
| parent | 7275576235ae2e87f3de7b0facb3f9b0a2368f28 (diff) | |
Merge branch 'master' into schema-alteration
Diffstat (limited to 'django/db')
| -rw-r--r-- | django/db/backends/__init__.py | 10 | ||||
| -rw-r--r-- | django/db/backends/creation.py | 3 | ||||
| -rw-r--r-- | django/db/backends/mysql/introspection.py | 3 | ||||
| -rw-r--r-- | django/db/backends/oracle/base.py | 22 | ||||
| -rw-r--r-- | django/db/backends/oracle/creation.py | 5 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/base.py | 16 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/creation.py | 3 | ||||
| -rw-r--r-- | django/db/models/base.py | 65 | ||||
| -rw-r--r-- | django/db/models/deletion.py | 25 | ||||
| -rw-r--r-- | django/db/models/fields/__init__.py | 21 | ||||
| -rw-r--r-- | django/db/models/fields/files.py | 4 | ||||
| -rw-r--r-- | django/db/models/fields/related.py | 14 | ||||
| -rw-r--r-- | django/db/models/loading.py | 5 | ||||
| -rw-r--r-- | django/db/models/options.py | 23 | ||||
| -rw-r--r-- | django/db/models/query.py | 23 | ||||
| -rw-r--r-- | django/db/models/query_utils.py | 5 | ||||
| -rw-r--r-- | django/db/models/related.py | 6 | ||||
| -rw-r--r-- | django/db/models/sql/compiler.py | 7 | ||||
| -rw-r--r-- | django/db/models/sql/query.py | 29 | ||||
| -rw-r--r-- | django/db/models/sql/subqueries.py | 11 |
20 files changed, 158 insertions, 142 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index b9c642d093..5719f51445 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -621,16 +621,16 @@ class BaseDatabaseOperations(object): exists for database backends to provide a better implementation according to their own quoting schemes. """ - from django.utils.encoding import smart_unicode, force_unicode + from django.utils.encoding import smart_text, force_text # Convert params to contain Unicode values. - to_unicode = lambda s: force_unicode(s, strings_only=True, errors='replace') + to_unicode = lambda s: force_text(s, strings_only=True, errors='replace') if isinstance(params, (list, tuple)): u_params = tuple([to_unicode(val) for val in params]) else: u_params = dict([(to_unicode(k), to_unicode(v)) for k, v in params.items()]) - return smart_unicode(sql) % u_params + return smart_text(sql) % u_params def last_insert_id(self, cursor, table_name, pk_name): """ @@ -814,8 +814,8 @@ class BaseDatabaseOperations(object): def prep_for_like_query(self, x): """Prepares a value for use in a LIKE query.""" - from django.utils.encoding import smart_unicode - return smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") + from django.utils.encoding import smart_text + return smart_text(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") # Same as prep_for_like_query(), but called for "iexact" matches, which # need not necessarily be implemented using "LIKE" in the backend. diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py index 4dffd78f44..0cc01cc876 100644 --- a/django/db/backends/creation.py +++ b/django/db/backends/creation.py @@ -3,6 +3,7 @@ import time from django.conf import settings from django.db.utils import load_backend +from django.utils.six.moves import input # The prefix to put on the default database name when creating # the test database. @@ -331,7 +332,7 @@ class BaseDatabaseCreation(object): sys.stderr.write( "Got an error creating the test database: %s\n" % e) if not autoclobber: - confirm = raw_input( + confirm = input( "Type 'yes' if you would like to try deleting the test " "database '%s', or 'no' to cancel: " % test_database_name) if autoclobber or confirm == 'yes': diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py index e6f18b819f..6aab0b99ab 100644 --- a/django/db/backends/mysql/introspection.py +++ b/django/db/backends/mysql/introspection.py @@ -1,4 +1,5 @@ from django.db.backends import BaseDatabaseIntrospection +from django.utils import six from MySQLdb import ProgrammingError, OperationalError from MySQLdb.constants import FIELD_TYPE import re @@ -79,7 +80,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): """ Returns the name of the primary key column for the given table """ - for column in self.get_indexes(cursor, table_name).iteritems(): + for column in six.iteritems(self.get_indexes(cursor, table_name)): if column[1]['primary_key']: return column[0] return None diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index b08113fed7..89cad12b6c 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -53,7 +53,7 @@ from django.db.backends.signals import connection_created from django.db.backends.oracle.client import DatabaseClient from django.db.backends.oracle.creation import DatabaseCreation from django.db.backends.oracle.introspection import DatabaseIntrospection -from django.utils.encoding import smart_str, force_unicode +from django.utils.encoding import smart_bytes, force_text from django.utils import six from django.utils import timezone @@ -64,9 +64,9 @@ IntegrityError = Database.IntegrityError # Check whether cx_Oracle was compiled with the WITH_UNICODE option. This will # also be True in Python 3.0. if int(Database.version.split('.', 1)[0]) >= 5 and not hasattr(Database, 'UNICODE'): - convert_unicode = force_unicode + convert_unicode = force_text else: - convert_unicode = smart_str + convert_unicode = smart_bytes class DatabaseFeatures(BaseDatabaseFeatures): @@ -162,7 +162,7 @@ WHEN (new.%(col_name)s IS NULL) if isinstance(value, Database.LOB): value = value.read() if field and field.get_internal_type() == 'TextField': - value = force_unicode(value) + value = force_text(value) # Oracle stores empty strings as null. We need to undo this in # order to adhere to the Django convention of using the empty @@ -245,7 +245,7 @@ WHEN (new.%(col_name)s IS NULL) def process_clob(self, value): if value is None: return '' - return force_unicode(value.read()) + return force_text(value.read()) def quote_name(self, name): # SQL92 requires delimited (quoted) names to be case-sensitive. When @@ -595,9 +595,9 @@ class OracleParam(object): param = param.astimezone(timezone.utc).replace(tzinfo=None) if hasattr(param, 'bind_parameter'): - self.smart_str = param.bind_parameter(cursor) + self.smart_bytes = param.bind_parameter(cursor) else: - self.smart_str = convert_unicode(param, cursor.charset, + self.smart_bytes = convert_unicode(param, cursor.charset, strings_only) if hasattr(param, 'input_size'): # If parameter has `input_size` attribute, use that. @@ -676,7 +676,7 @@ class FormatStylePlaceholderCursor(object): self.setinputsizes(*sizes) def _param_generator(self, params): - return [p.smart_str for p in params] + return [p.smart_bytes for p in params] def execute(self, query, params=None): if params is None: @@ -774,9 +774,11 @@ class CursorIterator(object): def __iter__(self): return self - def next(self): + def __next__(self): return _rowfactory(next(self.iter), self.cursor) + next = __next__ # Python 2 compatibility + def _rowfactory(row, cursor): # Cast numeric values as the appropriate Python type based upon the @@ -831,7 +833,7 @@ def to_unicode(s): unchanged). """ if isinstance(s, six.string_types): - return force_unicode(s) + return force_text(s) return s diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index 2f096f735a..d9bf3dfea2 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -1,6 +1,7 @@ import sys import time from django.db.backends.creation import BaseDatabaseCreation +from django.utils.six.moves import input TEST_DATABASE_PREFIX = 'test_' PASSWORD = 'Im_a_lumberjack' @@ -65,7 +66,7 @@ class DatabaseCreation(BaseDatabaseCreation): except Exception as e: sys.stderr.write("Got an error creating the test database: %s\n" % e) if not autoclobber: - confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_NAME) + confirm = input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_NAME) if autoclobber or confirm == 'yes': try: if verbosity >= 1: @@ -87,7 +88,7 @@ class DatabaseCreation(BaseDatabaseCreation): except Exception as e: sys.stderr.write("Got an error creating the test user: %s\n" % e) if not autoclobber: - confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_USER) + confirm = input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_USER) if autoclobber or confirm == 'yes': try: if verbosity >= 1: diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 0a97449789..0880079189 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -54,15 +54,15 @@ def adapt_datetime_with_timezone_support(value): default_timezone = timezone.get_default_timezone() value = timezone.make_aware(value, default_timezone) value = value.astimezone(timezone.utc).replace(tzinfo=None) - return value.isoformat(b" ") + return value.isoformat(str(" ")) -Database.register_converter(b"bool", lambda s: str(s) == '1') -Database.register_converter(b"time", parse_time) -Database.register_converter(b"date", parse_date) -Database.register_converter(b"datetime", parse_datetime_with_timezone_support) -Database.register_converter(b"timestamp", parse_datetime_with_timezone_support) -Database.register_converter(b"TIMESTAMP", parse_datetime_with_timezone_support) -Database.register_converter(b"decimal", util.typecast_decimal) +Database.register_converter(str("bool"), lambda s: str(s) == '1') +Database.register_converter(str("time"), parse_time) +Database.register_converter(str("date"), parse_date) +Database.register_converter(str("datetime"), parse_datetime_with_timezone_support) +Database.register_converter(str("timestamp"), parse_datetime_with_timezone_support) +Database.register_converter(str("TIMESTAMP"), parse_datetime_with_timezone_support) +Database.register_converter(str("decimal"), util.typecast_decimal) Database.register_adapter(datetime.datetime, adapt_datetime_with_timezone_support) Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal) if Database.version_info >= (2, 4, 1): diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py index efdc457be0..c022b56c85 100644 --- a/django/db/backends/sqlite3/creation.py +++ b/django/db/backends/sqlite3/creation.py @@ -1,6 +1,7 @@ import os import sys from django.db.backends.creation import BaseDatabaseCreation +from django.utils.six.moves import input class DatabaseCreation(BaseDatabaseCreation): # SQLite doesn't actually support most of these types, but it "does the right @@ -53,7 +54,7 @@ class DatabaseCreation(BaseDatabaseCreation): print("Destroying old test database '%s'..." % self.connection.alias) if os.access(test_database_name, os.F_OK): if not autoclobber: - confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name) + confirm = input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name) if autoclobber or confirm == 'yes': try: os.remove(test_database_name) diff --git a/django/db/models/base.py b/django/db/models/base.py index 002e2aff65..569b8e876c 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -23,11 +23,35 @@ from django.db.models import signals from django.db.models.loading import register_models, get_model from django.utils.translation import ugettext_lazy as _ from django.utils.functional import curry -from django.utils.encoding import smart_str, force_unicode +from django.utils.encoding import smart_bytes, force_text from django.utils import six from django.utils.text import get_text_list, capfirst +def subclass_exception(name, parents, module, attached_to=None): + """ + Create exception subclass. Used by ModelBase below. + + If 'attached_to' is supplied, the exception will be created in a way that + allows it to be pickled, assuming the returned exception class will be added + as an attribute to the 'attached_to' class. + """ + class_dict = {'__module__': module} + if attached_to is not None: + def __reduce__(self): + # Exceptions are special - they've got state that isn't + # in self.__dict__. We assume it is all in self.args. + return (unpickle_inner_exception, (attached_to, name), self.args) + + def __setstate__(self, args): + self.args = args + + class_dict['__reduce__'] = __reduce__ + class_dict['__setstate__'] = __setstate__ + + return type(name, parents, class_dict) + + class ModelBase(type): """ Metaclass for all models. @@ -63,12 +87,12 @@ class ModelBase(type): new_class.add_to_class('_meta', Options(meta, **kwargs)) if not abstract: - new_class.add_to_class('DoesNotExist', subclass_exception(b'DoesNotExist', + new_class.add_to_class('DoesNotExist', subclass_exception(str('DoesNotExist'), tuple(x.DoesNotExist for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (ObjectDoesNotExist,), module, attached_to=new_class)) - new_class.add_to_class('MultipleObjectsReturned', subclass_exception(b'MultipleObjectsReturned', + new_class.add_to_class('MultipleObjectsReturned', subclass_exception(str('MultipleObjectsReturned'), tuple(x.MultipleObjectsReturned for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (MultipleObjectsReturned,), @@ -364,14 +388,14 @@ class Model(six.with_metaclass(ModelBase, object)): setattr(self, field.attname, val) if kwargs: - for prop in kwargs.keys(): + for prop in list(kwargs): try: if isinstance(getattr(self.__class__, prop), property): setattr(self, prop, kwargs.pop(prop)) except AttributeError: pass if kwargs: - raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]) + raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0]) super(Model, self).__init__() signals.post_init.send(sender=self.__class__, instance=self) @@ -380,11 +404,11 @@ class Model(six.with_metaclass(ModelBase, object)): u = six.text_type(self) except (UnicodeEncodeError, UnicodeDecodeError): u = '[Bad Unicode data]' - return smart_str('<%s: %s>' % (self.__class__.__name__, u)) + return smart_bytes('<%s: %s>' % (self.__class__.__name__, u)) def __str__(self): if hasattr(self, '__unicode__'): - return force_unicode(self).encode('utf-8') + return force_text(self).encode('utf-8') return '%s object' % self.__class__.__name__ def __eq__(self, other): @@ -605,14 +629,14 @@ class Model(six.with_metaclass(ModelBase, object)): def _get_FIELD_display(self, field): value = getattr(self, field.attname) - return force_unicode(dict(field.flatchoices).get(value, value), strings_only=True) + return force_text(dict(field.flatchoices).get(value, value), strings_only=True) def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs): if not self.pk: raise ValueError("get_next/get_previous cannot be used on unsaved objects.") op = is_next and 'gt' or 'lt' order = not is_next and '-' or '' - param = smart_str(getattr(self, field.attname)) + param = smart_bytes(getattr(self, field.attname)) q = Q(**{'%s__%s' % (field.name, op): param}) q = q|Q(**{field.name: param, 'pk__%s' % op: self.pk}) qs = self.__class__._default_manager.using(self._state.db).filter(**kwargs).filter(q).order_by('%s%s' % (order, field.name), '%spk' % order) @@ -929,29 +953,6 @@ def model_unpickle(model, attrs): return cls.__new__(cls) model_unpickle.__safe_for_unpickle__ = True -def subclass_exception(name, parents, module, attached_to=None): - """ - Create exception subclass. - - If 'attached_to' is supplied, the exception will be created in a way that - allows it to be pickled, assuming the returned exception class will be added - as an attribute to the 'attached_to' class. - """ - class_dict = {'__module__': module} - if attached_to is not None: - def __reduce__(self): - # Exceptions are special - they've got state that isn't - # in self.__dict__. We assume it is all in self.args. - return (unpickle_inner_exception, (attached_to, name), self.args) - - def __setstate__(self, args): - self.args = args - - class_dict['__reduce__'] = __reduce__ - class_dict['__setstate__'] = __setstate__ - - return type(name, parents, class_dict) - def unpickle_inner_exception(klass, exception_name): # Get the exception class from the class it is attached to: exception = getattr(klass, exception_name) diff --git a/django/db/models/deletion.py b/django/db/models/deletion.py index d8bb8f2e66..4449b75a81 100644 --- a/django/db/models/deletion.py +++ b/django/db/models/deletion.py @@ -4,6 +4,7 @@ from operator import attrgetter from django.db import connections, transaction, IntegrityError from django.db.models import signals, sql from django.utils.datastructures import SortedDict +from django.utils import six class ProtectedError(IntegrityError): @@ -157,7 +158,7 @@ class Collector(object): # Recursively collect concrete model's parent models, but not their # related objects. These will be found by meta.get_all_related_objects() concrete_model = model._meta.concrete_model - for ptr in concrete_model._meta.parents.itervalues(): + for ptr in six.itervalues(concrete_model._meta.parents): if ptr: parent_objs = [getattr(obj, ptr.name) for obj in new_objs] self.collect(parent_objs, source=model, @@ -199,14 +200,14 @@ class Collector(object): ) def instances_with_model(self): - for model, instances in self.data.iteritems(): + for model, instances in six.iteritems(self.data): for obj in instances: yield model, obj def sort(self): sorted_models = [] concrete_models = set() - models = self.data.keys() + models = list(self.data) while len(sorted_models) < len(models): found = False for model in models: @@ -241,24 +242,24 @@ class Collector(object): ) # update fields - for model, instances_for_fieldvalues in self.field_updates.iteritems(): + for model, instances_for_fieldvalues in six.iteritems(self.field_updates): query = sql.UpdateQuery(model) - for (field, value), instances in instances_for_fieldvalues.iteritems(): + for (field, value), instances in six.iteritems(instances_for_fieldvalues): query.update_batch([obj.pk for obj in instances], {field.name: value}, self.using) # reverse instance collections - for instances in self.data.itervalues(): + for instances in six.itervalues(self.data): instances.reverse() # delete batches - for model, batches in self.batches.iteritems(): + for model, batches in six.iteritems(self.batches): query = sql.DeleteQuery(model) - for field, instances in batches.iteritems(): + for field, instances in six.iteritems(batches): query.delete_batch([obj.pk for obj in instances], self.using, field) # delete instances - for model, instances in self.data.iteritems(): + for model, instances in six.iteritems(self.data): query = sql.DeleteQuery(model) pk_list = [obj.pk for obj in instances] query.delete_batch(pk_list, self.using) @@ -271,10 +272,10 @@ class Collector(object): ) # update collected instances - for model, instances_for_fieldvalues in self.field_updates.iteritems(): - for (field, value), instances in instances_for_fieldvalues.iteritems(): + for model, instances_for_fieldvalues in six.iteritems(self.field_updates): + for (field, value), instances in six.iteritems(instances_for_fieldvalues): for obj in instances: setattr(obj, field.attname, value) - for model, instances in self.data.iteritems(): + for model, instances in six.iteritems(self.data): for instance in instances: setattr(instance, model._meta.pk.attname, None) diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 9606b1b843..d07851bbf5 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -19,7 +19,7 @@ from django.utils.functional import curry, total_ordering from django.utils.text import capfirst from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from django.utils.encoding import smart_unicode, force_unicode +from django.utils.encoding import smart_text, force_text from django.utils.ipv6 import clean_ipv6_address from django.utils import six @@ -135,6 +135,8 @@ class Field(object): return self.creation_counter < other.creation_counter return NotImplemented + __hash__ = object.__hash__ + def __deepcopy__(self, memodict): # We don't have to deepcopy very much here, since most things are not # intended to be altered after initial creation. @@ -179,7 +181,8 @@ class Field(object): if not self.editable: # Skip validation for non-editable fields. return - if self._choices and value: + + if self._choices and value not in validators.EMPTY_VALUES: for option_key, option_value in self.choices: if isinstance(option_value, (list, tuple)): # This is an optgroup, so look inside the group for @@ -385,7 +388,7 @@ class Field(object): if self.has_default(): if callable(self.default): return self.default() - return force_unicode(self.default, strings_only=True) + return force_text(self.default, strings_only=True) if (not self.empty_strings_allowed or (self.null and not connection.features.interprets_empty_strings_as_nulls)): return None @@ -403,11 +406,11 @@ class Field(object): rel_model = self.rel.to if hasattr(self.rel, 'get_related_field'): lst = [(getattr(x, self.rel.get_related_field().attname), - smart_unicode(x)) + smart_text(x)) for x in rel_model._default_manager.complex_filter( self.rel.limit_choices_to)] else: - lst = [(x._get_pk_val(), smart_unicode(x)) + lst = [(x._get_pk_val(), smart_text(x)) for x in rel_model._default_manager.complex_filter( self.rel.limit_choices_to)] return first_choice + lst @@ -434,7 +437,7 @@ class Field(object): Returns a string value of this field from the passed obj. This is used by the serialization framework. """ - return smart_unicode(self._get_val_from_obj(obj)) + return smart_text(self._get_val_from_obj(obj)) def bind(self, fieldmapping, original, bound_field_class): return bound_field_class(self, fieldmapping, original) @@ -486,7 +489,7 @@ class Field(object): # Many of the subclass-specific formfield arguments (min_value, # max_value) don't apply for choice fields, so be sure to only pass # the values that TypedChoiceField will understand. - for k in kwargs.keys(): + for k in list(kwargs): if k not in ('coerce', 'empty_value', 'choices', 'required', 'widget', 'label', 'initial', 'help_text', 'error_messages', 'show_hidden_initial'): @@ -628,7 +631,7 @@ class CharField(Field): def to_python(self, value): if isinstance(value, six.string_types) or value is None: return value - return smart_unicode(value) + return smart_text(value) def get_prep_value(self, value): return self.to_python(value) @@ -1188,7 +1191,7 @@ class TextField(Field): def get_prep_value(self, value): if isinstance(value, six.string_types) or value is None: return value - return smart_unicode(value) + return smart_text(value) def formfield(self, **kwargs): defaults = {'widget': forms.Textarea} diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index b51ef1d5d6..ad4c36ca0d 100644 --- a/django/db/models/fields/files.py +++ b/django/db/models/fields/files.py @@ -8,7 +8,7 @@ from django.core.files.base import File from django.core.files.storage import default_storage from django.core.files.images import ImageFile from django.db.models import signals -from django.utils.encoding import force_unicode, smart_str +from django.utils.encoding import force_text, smart_bytes from django.utils import six from django.utils.translation import ugettext_lazy as _ @@ -280,7 +280,7 @@ class FileField(Field): setattr(cls, self.name, self.descriptor_class(self)) def get_directory_name(self): - return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to)))) + return os.path.normpath(force_text(datetime.datetime.now().strftime(smart_bytes(self.upload_to)))) def get_filename(self, filename): return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename))) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 2a2502b54f..08cc0a747f 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -9,7 +9,7 @@ from django.db.models.related import RelatedObject from django.db.models.query import QuerySet from django.db.models.query_utils import QueryWrapper from django.db.models.deletion import CASCADE -from django.utils.encoding import smart_unicode +from django.utils.encoding import smart_text from django.utils import six from django.utils.translation import ugettext_lazy as _, string_concat from django.utils.functional import curry, cached_property @@ -241,7 +241,7 @@ class SingleRelatedObjectDescriptor(object): rel_obj_attr = attrgetter(self.related.field.attname) instance_attr = lambda obj: obj._get_pk_val() instances_dict = dict((instance_attr(inst), inst) for inst in instances) - params = {'%s__pk__in' % self.related.field.name: instances_dict.keys()} + params = {'%s__pk__in' % self.related.field.name: list(instances_dict)} qs = self.get_query_set(instance=instances[0]).filter(**params) # Since we're going to assign directly in the cache, # we must manage the reverse relation cache manually. @@ -335,9 +335,9 @@ class ReverseSingleRelatedObjectDescriptor(object): instance_attr = attrgetter(self.field.attname) instances_dict = dict((instance_attr(inst), inst) for inst in instances) if other_field.rel: - params = {'%s__pk__in' % self.field.rel.field_name: instances_dict.keys()} + params = {'%s__pk__in' % self.field.rel.field_name: list(instances_dict)} else: - params = {'%s__in' % self.field.rel.field_name: instances_dict.keys()} + params = {'%s__in' % self.field.rel.field_name: list(instances_dict)} qs = self.get_query_set(instance=instances[0]).filter(**params) # Since we're going to assign directly in the cache, # we must manage the reverse relation cache manually. @@ -488,7 +488,7 @@ class ForeignRelatedObjectsDescriptor(object): instance_attr = attrgetter(attname) instances_dict = dict((instance_attr(inst), inst) for inst in instances) db = self._db or router.db_for_read(self.model, instance=instances[0]) - query = {'%s__%s__in' % (rel_field.name, attname): instances_dict.keys()} + query = {'%s__%s__in' % (rel_field.name, attname): list(instances_dict)} qs = super(RelatedManager, self).get_query_set().using(db).filter(**query) # Since we just bypassed this class' get_query_set(), we must manage # the reverse relation manually. @@ -999,7 +999,7 @@ class ForeignKey(RelatedField, Field): if not self.blank and self.choices: choice_list = self.get_choices_default() if len(choice_list) == 2: - return smart_unicode(choice_list[1][0]) + return smart_text(choice_list[1][0]) return Field.value_to_string(self, obj) def contribute_to_class(self, cls, name): @@ -1205,7 +1205,7 @@ class ManyToManyField(RelatedField, Field): choices_list = self.get_choices_default() if len(choices_list) == 1: data = [choices_list[0][0]] - return smart_unicode(data) + return smart_text(data) def contribute_to_class(self, cls, name): # To support multiple relations to self, it's useful to have a non-None diff --git a/django/db/models/loading.py b/django/db/models/loading.py index d651584e7a..7a9cb2cb41 100644 --- a/django/db/models/loading.py +++ b/django/db/models/loading.py @@ -5,6 +5,7 @@ from django.core.exceptions import ImproperlyConfigured from django.utils.datastructures import SortedDict from django.utils.importlib import import_module from django.utils.module_loading import module_has_submodule +from django.utils import six import imp import sys @@ -193,9 +194,9 @@ class AppCache(object): else: if only_installed: app_list = [self.app_models.get(app_label, SortedDict()) - for app_label in self.app_labels.iterkeys()] + for app_label in six.iterkeys(self.app_labels)] else: - app_list = self.app_models.itervalues() + app_list = six.itervalues(self.app_models) model_list = [] for app in app_list: model_list.extend( diff --git a/django/db/models/options.py b/django/db/models/options.py index 7308a15c6b..2e8ccb49ce 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -8,7 +8,7 @@ from django.db.models.fields import AutoField, FieldDoesNotExist from django.db.models.fields.proxy import OrderWrt from django.db.models.loading import get_models, app_cache_ready from django.utils.translation import activate, deactivate_all, get_language, string_concat -from django.utils.encoding import force_unicode, smart_str +from django.utils.encoding import force_text, smart_bytes from django.utils.datastructures import SortedDict from django.utils import six @@ -127,7 +127,7 @@ class Options(object): if self.parents: # Promote the first parent link in lieu of adding yet another # field. - field = next(self.parents.itervalues()) + field = next(six.itervalues(self.parents)) # Look for a local field with the same name as the # first parent link. If a local field has already been # created, use it instead of promoting the parent @@ -147,13 +147,13 @@ class Options(object): # self.duplicate_targets will map each duplicate field column to the # columns it duplicates. collections = {} - for column, target in self.duplicate_targets.iteritems(): + for column, target in six.iteritems(self.duplicate_targets): try: collections[target].add(column) except KeyError: collections[target] = set([column]) self.duplicate_targets = {} - for elt in collections.itervalues(): + for elt in six.itervalues(collections): if len(elt) == 1: continue for column in elt: @@ -199,7 +199,7 @@ class Options(object): return '<Options for %s>' % self.object_name def __str__(self): - return "%s.%s" % (smart_str(self.app_label), smart_str(self.module_name)) + return "%s.%s" % (smart_bytes(self.app_label), smart_bytes(self.module_name)) def verbose_name_raw(self): """ @@ -209,7 +209,7 @@ class Options(object): """ lang = get_language() deactivate_all() - raw = force_unicode(self.verbose_name) + raw = force_text(self.verbose_name) activate(lang) return raw verbose_name_raw = property(verbose_name_raw) @@ -258,7 +258,7 @@ class Options(object): self._m2m_cache except AttributeError: self._fill_m2m_cache() - return self._m2m_cache.keys() + return list(self._m2m_cache) many_to_many = property(_many_to_many) def get_m2m_with_model(self): @@ -269,7 +269,7 @@ class Options(object): self._m2m_cache except AttributeError: self._fill_m2m_cache() - return self._m2m_cache.items() + return list(six.iteritems(self._m2m_cache)) def _fill_m2m_cache(self): cache = SortedDict() @@ -326,8 +326,7 @@ class Options(object): cache = self._name_map except AttributeError: cache = self.init_name_map() - names = cache.keys() - names.sort() + names = sorted(cache.keys()) # Internal-only names end with "+" (symmetrical m2m related names being # the main example). Trim them. return [val for val in names if not val.endswith('+')] @@ -417,7 +416,7 @@ class Options(object): cache = self._fill_related_many_to_many_cache() if local_only: return [k for k, v in cache.items() if not v] - return cache.keys() + return list(cache) def get_all_related_m2m_objects_with_model(self): """ @@ -428,7 +427,7 @@ class Options(object): cache = self._related_many_to_many_cache except AttributeError: cache = self._fill_related_many_to_many_cache() - return cache.items() + return list(six.iteritems(cache)) def _fill_related_many_to_many_cache(self): cache = SortedDict() diff --git a/django/db/models/query.py b/django/db/models/query.py index 8b6b42b7b1..e8d6ae2a7b 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -120,7 +120,7 @@ class QuerySet(object): if len(self._result_cache) <= pos: self._fill_cache() - def __nonzero__(self): + def __bool__(self): if self._prefetch_related_lookups and not self._prefetch_done: # We need all the results in order to be able to do the prefetch # in one go. To minimize code duplication, we use the __len__ @@ -134,6 +134,7 @@ class QuerySet(object): except StopIteration: return False return True + __nonzero__ = __bool__ # Python 2 def __contains__(self, val): # The 'in' operator works without this method, due to __iter__. This @@ -245,8 +246,8 @@ class QuerySet(object): requested = None max_depth = self.query.max_depth - extra_select = self.query.extra_select.keys() - aggregate_select = self.query.aggregate_select.keys() + extra_select = list(self.query.extra_select) + aggregate_select = list(self.query.aggregate_select) only_load = self.query.get_loaded_field_names() if not fill_cache: @@ -593,7 +594,7 @@ class QuerySet(object): flat = kwargs.pop('flat', False) if kwargs: raise TypeError('Unexpected keyword arguments to values_list: %s' - % (kwargs.keys(),)) + % (list(kwargs),)) if flat and len(fields) > 1: raise TypeError("'flat' is not valid when values_list is called with more than one field.") return self._clone(klass=ValuesListQuerySet, setup=True, flat=flat, @@ -693,7 +694,7 @@ class QuerySet(object): depth = kwargs.pop('depth', 0) if kwargs: raise TypeError('Unexpected keyword arguments to select_related: %s' - % (kwargs.keys(),)) + % (list(kwargs),)) obj = self._clone() if fields: if depth: @@ -751,7 +752,7 @@ class QuerySet(object): obj = self._clone() - obj._setup_aggregate_query(kwargs.keys()) + obj._setup_aggregate_query(list(kwargs)) # Add the aggregates to the query for (alias, aggregate_expr) in kwargs.items(): @@ -966,9 +967,9 @@ class ValuesQuerySet(QuerySet): def iterator(self): # Purge any extra columns that haven't been explicitly asked for - extra_names = self.query.extra_select.keys() + extra_names = list(self.query.extra_select) field_names = self.field_names - aggregate_names = self.query.aggregate_select.keys() + aggregate_names = list(self.query.aggregate_select) names = extra_names + field_names + aggregate_names @@ -1097,9 +1098,9 @@ class ValuesListQuerySet(ValuesQuerySet): # When extra(select=...) or an annotation is involved, the extra # cols are always at the start of the row, and we need to reorder # the fields to match the order in self._fields. - extra_names = self.query.extra_select.keys() + extra_names = list(self.query.extra_select) field_names = self.field_names - aggregate_names = self.query.aggregate_select.keys() + aggregate_names = list(self.query.aggregate_select) names = extra_names + field_names + aggregate_names @@ -1527,7 +1528,7 @@ class RawQuerySet(object): # Associate fields to values if skip: model_init_kwargs = {} - for attname, pos in model_init_field_names.iteritems(): + for attname, pos in six.iteritems(model_init_field_names): model_init_kwargs[attname] = values[pos] instance = model_cls(**model_init_kwargs) else: diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py index 60bdb2bcb4..c1a690a524 100644 --- a/django/db/models/query_utils.py +++ b/django/db/models/query_utils.py @@ -8,6 +8,7 @@ circular import difficulties. from __future__ import unicode_literals from django.db.backends import util +from django.utils import six from django.utils import tree @@ -40,7 +41,7 @@ class Q(tree.Node): default = AND def __init__(self, *args, **kwargs): - super(Q, self).__init__(children=list(args) + kwargs.items()) + super(Q, self).__init__(children=list(args) + list(six.iteritems(kwargs))) def _combine(self, other, conn): if not isinstance(other, Q): @@ -114,7 +115,7 @@ class DeferredAttribute(object): def _check_parent_chain(self, instance, name): """ - Check if the field value can be fetched from a parent field already + Check if the field value can be fetched from a parent field already loaded in the instance. This can be done if the to-be fetched field is a primary key field. """ diff --git a/django/db/models/related.py b/django/db/models/related.py index 90995d749f..a0dcec7132 100644 --- a/django/db/models/related.py +++ b/django/db/models/related.py @@ -1,4 +1,4 @@ -from django.utils.encoding import smart_unicode +from django.utils.encoding import smart_text from django.db.models.fields import BLANK_CHOICE_DASH class BoundRelatedObject(object): @@ -34,9 +34,9 @@ class RelatedObject(object): if limit_to_currently_related: queryset = queryset.complex_filter( {'%s__isnull' % self.parent_model._meta.module_name: False}) - lst = [(x._get_pk_val(), smart_unicode(x)) for x in queryset] + lst = [(x._get_pk_val(), smart_text(x)) for x in queryset] return first_choice + lst - + def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False): # Defer to the actual field definition for db prep return self.field.get_db_prep_lookup(lookup_type, value, diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 7a0afa349d..1311ea546c 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -9,6 +9,7 @@ from django.db.models.sql.datastructures import EmptyResultSet from django.db.models.sql.expressions import SQLEvaluator from django.db.models.sql.query import get_order_dir, Query from django.db.utils import DatabaseError +from django.utils import six class SQLCompiler(object): @@ -82,7 +83,7 @@ class SQLCompiler(object): where, w_params = self.query.where.as_sql(qn=qn, connection=self.connection) having, h_params = self.query.having.as_sql(qn=qn, connection=self.connection) params = [] - for val in self.query.extra_select.itervalues(): + for val in six.itervalues(self.query.extra_select): params.extend(val[1]) result = ['SELECT'] @@ -177,7 +178,7 @@ class SQLCompiler(object): """ qn = self.quote_name_unless_alias qn2 = self.connection.ops.quote_name - result = ['(%s) AS %s' % (col[0], qn2(alias)) for alias, col in self.query.extra_select.iteritems()] + result = ['(%s) AS %s' % (col[0], qn2(alias)) for alias, col in six.iteritems(self.query.extra_select)] aliases = set(self.query.extra_select.keys()) if with_aliases: col_aliases = aliases.copy() @@ -553,7 +554,7 @@ class SQLCompiler(object): group_by = self.query.group_by or [] extra_selects = [] - for extra_select, extra_params in self.query.extra_select.itervalues(): + for extra_select, extra_params in six.itervalues(self.query.extra_select): extra_selects.append(extra_select) params.extend(extra_params) cols = (group_by + self.query.select + diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 53dad608bf..be257a5410 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -10,8 +10,9 @@ all about the internals of models in order to get the information it needs. import copy from django.utils.datastructures import SortedDict -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.tree import Node +from django.utils import six from django.db import connections, DEFAULT_DB_ALIAS from django.db.models import signals from django.db.models.expressions import ExpressionNode @@ -602,22 +603,22 @@ class Query(object): # slight complexity here is handling fields that exist on parent # models. workset = {} - for model, values in seen.iteritems(): + for model, values in six.iteritems(seen): for field, m in model._meta.get_fields_with_model(): if field in values: continue add_to_dict(workset, m or model, field) - for model, values in must_include.iteritems(): + for model, values in six.iteritems(must_include): # If we haven't included a model in workset, we don't add the # corresponding must_include fields for that model, since an # empty set means "include all fields". That's why there's no # "else" branch here. if model in workset: workset[model].update(values) - for model, values in workset.iteritems(): + for model, values in six.iteritems(workset): callback(target, model, values) else: - for model, values in must_include.iteritems(): + for model, values in six.iteritems(must_include): if model in seen: seen[model].update(values) else: @@ -631,7 +632,7 @@ class Query(object): for model in orig_opts.get_parent_list(): if model not in seen: seen[model] = set() - for model, values in seen.iteritems(): + for model, values in six.iteritems(seen): callback(target, model, values) @@ -770,7 +771,7 @@ class Query(object): for k, aliases in self.join_map.items(): aliases = tuple([change_map.get(a, a) for a in aliases]) self.join_map[k] = aliases - for old_alias, new_alias in change_map.iteritems(): + for old_alias, new_alias in six.iteritems(change_map): alias_data = self.alias_map[old_alias] alias_data = alias_data._replace(rhs_alias=new_alias) self.alias_refcount[new_alias] = self.alias_refcount[old_alias] @@ -792,7 +793,7 @@ class Query(object): self.included_inherited_models[key] = change_map[alias] # 3. Update any joins that refer to the old alias. - for alias, data in self.alias_map.iteritems(): + for alias, data in six.iteritems(self.alias_map): lhs = data.lhs_alias if lhs in change_map: data = data._replace(lhs_alias=change_map[lhs]) @@ -842,7 +843,7 @@ class Query(object): count. Note that after execution, the reference counts are zeroed, so tables added in compiler will not be seen by this method. """ - return len([1 for count in self.alias_refcount.itervalues() if count]) + return len([1 for count in six.itervalues(self.alias_refcount) if count]) def join(self, connection, always_create=False, exclusions=(), promote=False, outer_if_first=False, nullable=False, reuse=None): @@ -1302,7 +1303,7 @@ class Query(object): field, model, direct, m2m = opts.get_field_by_name(f.name) break else: - names = opts.get_all_field_names() + self.aggregate_select.keys() + names = opts.get_all_field_names() + list(self.aggregate_select) raise FieldError("Cannot resolve keyword %r into field. " "Choices are: %s" % (name, ", ".join(names))) @@ -1571,7 +1572,7 @@ class Query(object): # Tag.objects.exclude(parent__parent__name='t1'), a tag with no parent # would otherwise be overlooked). active_positions = [pos for (pos, count) in - enumerate(query.alias_refcount.itervalues()) if count] + enumerate(six.itervalues(query.alias_refcount)) if count] if active_positions[-1] > 1: self.add_filter(('%s__isnull' % prefix, False), negate=True, trim=True, can_reuse=can_reuse) @@ -1660,8 +1661,8 @@ class Query(object): # from the model on which the lookup failed. raise else: - names = sorted(opts.get_all_field_names() + self.extra.keys() - + self.aggregate_select.keys()) + names = sorted(opts.get_all_field_names() + list(self.extra) + + list(self.aggregate_select)) raise FieldError("Cannot resolve keyword %r into field. " "Choices are: %s" % (name, ", ".join(names))) self.remove_inherited_models() @@ -1775,7 +1776,7 @@ class Query(object): else: param_iter = iter([]) for name, entry in select.items(): - entry = force_unicode(entry) + entry = force_text(entry) entry_params = [] pos = entry.find("%s") while pos != -1: diff --git a/django/db/models/sql/subqueries.py b/django/db/models/sql/subqueries.py index 7b92394e90..937505b9b0 100644 --- a/django/db/models/sql/subqueries.py +++ b/django/db/models/sql/subqueries.py @@ -10,7 +10,8 @@ from django.db.models.sql.query import Query from django.db.models.sql.where import AND, Constraint from django.utils.datastructures import SortedDict from django.utils.functional import Promise -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text +from django.utils import six __all__ = ['DeleteQuery', 'UpdateQuery', 'InsertQuery', 'DateQuery', @@ -87,7 +88,7 @@ class UpdateQuery(Query): querysets. """ values_seq = [] - for name, val in values.iteritems(): + for name, val in six.iteritems(values): field, model, direct, m2m = self.model._meta.get_field_by_name(name) if not direct or m2m: raise FieldError('Cannot update model field %r (only non-relations and foreign keys permitted).' % field) @@ -104,7 +105,7 @@ class UpdateQuery(Query): saving models. """ # Check that no Promise object passes to the query. Refs #10498. - values_seq = [(value[0], value[1], force_unicode(value[2])) + values_seq = [(value[0], value[1], force_text(value[2])) if isinstance(value[2], Promise) else value for value in values_seq] self.values.extend(values_seq) @@ -129,7 +130,7 @@ class UpdateQuery(Query): if not self.related_updates: return [] result = [] - for model, values in self.related_updates.iteritems(): + for model, values in six.iteritems(self.related_updates): query = UpdateQuery(model) query.values = values if self.related_ids is not None: @@ -170,7 +171,7 @@ class InsertQuery(Query): for obj in objs: value = getattr(obj, field.attname) if isinstance(value, Promise): - setattr(obj, field.attname, force_unicode(value)) + setattr(obj, field.attname, force_text(value)) self.objs = objs self.raw = raw |
