diff -Nru python-django-1.7.1/debian/changelog python-django-1.7.3/debian/changelog
--- python-django-1.7.1/debian/changelog	2014-10-27 16:57:12.000000000 +0100
+++ python-django-1.7.3/debian/changelog	2015-01-16 06:44:39.000000000 +0100
@@ -1,3 +1,23 @@
+python-django (1.7.3-1) UNRELEASED; urgency=high
+
+  * New upstream security release.
+    - WSGI header spoofing via underscore/dash conflation (CVE-2015-0219)
+    - Possible XSS attack via user-supplied redirect URLs (CVE-2015-0220)
+    - DoS attack against django.views.static.serve (CVE-2015-0221)
+    - Database DoS with ModelMultipleChoiceField (CVE-2015-0222)
+
+ -- Luke Faraone <lfaraone@debian.org>  Thu, 15 Jan 2015 21:42:11 -0800
+
+python-django (1.7.2-1) experimental; urgency=medium
+
+  [ Raphaël Hertzog ]
+  * Add geoip-database-extra as an alternative to geoip-database-contrib.
+
+  [ Brian May ]
+  * New upstream version.
+
+ -- Brian May <bam@debian.org>  Mon, 05 Jan 2015 13:57:16 +1100
+
 python-django (1.7.1-1) unstable; urgency=medium
 
   [ Raphaël Hertzog ]
diff -Nru python-django-1.7.1/debian/control python-django-1.7.3/debian/control
--- python-django-1.7.1/debian/control	2014-10-27 16:57:12.000000000 +0100
+++ python-django-1.7.3/debian/control	2015-01-16 06:44:39.000000000 +0100
@@ -29,7 +29,7 @@
 Architecture: all
 Depends: ${misc:Depends}, ${python:Depends}, python-django-common (= ${binary:Version})
 Recommends: libjs-jquery, python-sqlparse, python-tz
-Suggests: python-psycopg2, python-mysqldb, python-flup, python-sqlite, python-memcache, python-pil, python-bcrypt, python-yaml, geoip-database-contrib, gettext, python-django-doc, ipython, bpython, libgdal1
+Suggests: python-psycopg2, python-mysqldb, python-flup, python-sqlite, python-memcache, python-pil, python-bcrypt, python-yaml, geoip-database-extra | geoip-database-contrib, gettext, python-django-doc, ipython, bpython, libgdal1
 Description: High-level Python web development framework (Python 2 version)
  Django is a high-level web application framework that loosely follows the
  model-view-controller design pattern.
diff -Nru python-django-1.7.1/debian/gbp.conf python-django-1.7.3/debian/gbp.conf
--- python-django-1.7.1/debian/gbp.conf	2014-10-27 16:57:12.000000000 +0100
+++ python-django-1.7.3/debian/gbp.conf	2015-01-16 06:44:39.000000000 +0100
@@ -1,3 +1,3 @@
 [DEFAULT]
 upstream-branch=upstream/1.7.x
-debian-branch=debian/sid
+debian-branch=debian/experimental
diff -Nru python-django-1.7.1/django/apps/registry.py python-django-1.7.3/django/apps/registry.py
--- python-django-1.7.1/django/apps/registry.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/apps/registry.py	2015-01-13 19:28:00.000000000 +0100
@@ -208,9 +208,17 @@
         model_name = model._meta.model_name
         app_models = self.all_models[app_label]
         if model_name in app_models:
-            raise RuntimeError(
-                "Conflicting '%s' models in application '%s': %s and %s." %
-                (model_name, app_label, app_models[model_name], model))
+            if (model.__name__ == app_models[model_name].__name__ and
+                    model.__module__ == app_models[model_name].__module__):
+                warnings.warn(
+                    "Model '%s.%s' was already registered. "
+                    "Reloading models is not advised as it can lead to inconsistencies, "
+                    "most notably with related models." % (model_name, app_label),
+                    RuntimeWarning, stacklevel=2)
+            else:
+                raise RuntimeError(
+                    "Conflicting '%s' models in application '%s': %s and %s." %
+                    (model_name, app_label, app_models[model_name], model))
         app_models[model_name] = model
         self.clear_cache()
 
diff -Nru python-django-1.7.1/django/conf/locale/el/formats.py python-django-1.7.3/django/conf/locale/el/formats.py
--- python-django-1.7.1/django/conf/locale/el/formats.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/conf/locale/el/formats.py	2015-01-13 19:28:05.000000000 +0100
@@ -5,20 +5,34 @@
 
 # The *_FORMAT strings use the Django date format syntax,
 # see http://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
-DATE_FORMAT = 'd E Y'
-TIME_FORMAT = 'g:i:s A'
-# DATETIME_FORMAT =
+DATE_FORMAT = 'd/m/Y'
+TIME_FORMAT = 'P'
+DATETIME_FORMAT = 'd/m/Y P'
 YEAR_MONTH_FORMAT = 'F Y'
 MONTH_DAY_FORMAT = 'j F'
-SHORT_DATE_FORMAT = 'd M Y'
-# SHORT_DATETIME_FORMAT =
-# FIRST_DAY_OF_WEEK =
+SHORT_DATE_FORMAT = 'd/m/Y'
+SHORT_DATETIME_FORMAT = 'd/m/Y P'
+FIRST_DAY_OF_WEEK = 0  # Sunday
 
 # The *_INPUT_FORMATS strings use the Python strftime format syntax,
 # see http://docs.python.org/library/datetime.html#strftime-strptime-behavior
-# DATE_INPUT_FORMATS =
-# TIME_INPUT_FORMATS =
-# DATETIME_INPUT_FORMATS =
+DATE_INPUT_FORMATS = (
+    '%d/%m/%Y', '%d/%m/%y', '%Y-%m-%d',  # '25/10/2006', '25/10/06', '2006-10-25',
+)
+DATETIME_INPUT_FORMATS = (
+    '%d/%m/%Y %H:%M:%S',     # '25/10/2006 14:30:59'
+    '%d/%m/%Y %H:%M:%S.%f',  # '25/10/2006 14:30:59.000200'
+    '%d/%m/%Y %H:%M',        # '25/10/2006 14:30'
+    '%d/%m/%Y',              # '25/10/2006'
+    '%d/%m/%y %H:%M:%S',     # '25/10/06 14:30:59'
+    '%d/%m/%y %H:%M:%S.%f',  # '25/10/06 14:30:59.000200'
+    '%d/%m/%y %H:%M',        # '25/10/06 14:30'
+    '%d/%m/%y',              # '25/10/06'
+    '%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59'
+    '%Y-%m-%d %H:%M:%S.%f',  # '2006-10-25 14:30:59.000200'
+    '%Y-%m-%d %H:%M',        # '2006-10-25 14:30'
+    '%Y-%m-%d',              # '2006-10-25'
+)
 DECIMAL_SEPARATOR = ','
-THOUSAND_SEPARATOR = '.'
-# NUMBER_GROUPING =
+THOUSAND_SEPARATOR = '\xa0'  # non-breaking space
+NUMBER_GROUPING = 3
Les fichiers binaires /tmp/M_VVsfwydl/python-django-1.7.1/django/conf/locale/ko/LC_MESSAGES/django.mo et /tmp/EiDjvFsVap/python-django-1.7.3/django/conf/locale/ko/LC_MESSAGES/django.mo sont différents
diff -Nru python-django-1.7.1/django/conf/locale/ko/LC_MESSAGES/django.po python-django-1.7.3/django/conf/locale/ko/LC_MESSAGES/django.po
--- python-django-1.7.1/django/conf/locale/ko/LC_MESSAGES/django.po	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/conf/locale/ko/LC_MESSAGES/django.po	2015-01-06 02:20:47.000000000 +0100
@@ -5,13 +5,14 @@
 # Jaehong Kim <mixe@korea.com>, 2011
 # Jannis Leidel <jannis@leidel.info>, 2011
 # Jeong Seongtae <magno79@gmail.com>, 2014
+# JuneHyeon Bae <devunt@gmail.com>, 2014
 msgid ""
 msgstr ""
 "Project-Id-Version: django\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2014-08-23 14:10+0200\n"
-"PO-Revision-Date: 2014-08-24 08:52+0000\n"
-"Last-Translator: Jannis Leidel <jannis@leidel.info>\n"
+"PO-Revision-Date: 2014-12-14 04:22+0000\n"
+"Last-Translator: JuneHyeon Bae <devunt@gmail.com>\n"
 "Language-Team: Korean (http://www.transifex.com/projects/p/django/language/"
 "ko/)\n"
 "MIME-Version: 1.0\n"
@@ -1242,41 +1243,41 @@
 #, python-format
 msgid "%d year"
 msgid_plural "%d years"
-msgstr[0] "%d "
+msgstr[0] "%d년"
 
 #: utils/timesince.py:26
 #, python-format
 msgid "%d month"
 msgid_plural "%d months"
-msgstr[0] "%d 2개월"
+msgstr[0] "%d개월"
 
 #: utils/timesince.py:27
 #, python-format
 msgid "%d week"
 msgid_plural "%d weeks"
-msgstr[0] "%d "
+msgstr[0] "%d주"
 
 #: utils/timesince.py:28
 #, python-format
 msgid "%d day"
 msgid_plural "%d days"
-msgstr[0] "%d "
+msgstr[0] "%d일"
 
 #: utils/timesince.py:29
 #, python-format
 msgid "%d hour"
 msgid_plural "%d hours"
-msgstr[0] "%d "
+msgstr[0] "%d시간"
 
 #: utils/timesince.py:30
 #, python-format
 msgid "%d minute"
 msgid_plural "%d minutes"
-msgstr[0] "%d "
+msgstr[0] "%d분"
 
 #: utils/timesince.py:46
 msgid "0 minutes"
-msgstr "0"
+msgstr "0분"
 
 #: views/csrf.py:105
 msgid "Forbidden"
diff -Nru python-django-1.7.1/django/conf/locale/uk/formats.py python-django-1.7.3/django/conf/locale/uk/formats.py
--- python-django-1.7.1/django/conf/locale/uk/formats.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/conf/locale/uk/formats.py	2015-01-13 19:28:00.000000000 +0100
@@ -13,7 +13,7 @@
 MONTH_DAY_FORMAT = 'j F'
 SHORT_DATE_FORMAT = 'j M Y'
 # SHORT_DATETIME_FORMAT =
-# FIRST_DAY_OF_WEEK =
+FIRST_DAY_OF_WEEK = 1  # Monday
 
 # The *_INPUT_FORMATS strings use the Python strftime format syntax,
 # see http://docs.python.org/library/datetime.html#strftime-strptime-behavior
diff -Nru python-django-1.7.1/django/contrib/admin/actions.py python-django-1.7.3/django/contrib/admin/actions.py
--- python-django-1.7.1/django/contrib/admin/actions.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/admin/actions.py	2015-01-13 19:28:00.000000000 +0100
@@ -63,16 +63,17 @@
     else:
         title = _("Are you sure?")
 
-    context = {
-        "title": title,
-        "objects_name": objects_name,
-        "deletable_objects": [deletable_objects],
-        'queryset': queryset,
-        "perms_lacking": perms_needed,
-        "protected": protected,
-        "opts": opts,
-        'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
-    }
+    context = dict(
+        modeladmin.admin_site.each_context(),
+        title=title,
+        objects_name=objects_name,
+        deletable_objects=[deletable_objects],
+        queryset=queryset,
+        perms_lacking=perms_needed,
+        protected=protected,
+        opts=opts,
+        action_checkbox_name=helpers.ACTION_CHECKBOX_NAME,
+    )
 
     # Display the confirmation page
     return TemplateResponse(request, modeladmin.delete_selected_confirmation_template or [
diff -Nru python-django-1.7.1/django/contrib/admin/checks.py python-django-1.7.3/django/contrib/admin/checks.py
--- python-django-1.7.1/django/contrib/admin/checks.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/admin/checks.py	2015-01-13 19:28:00.000000000 +0100
@@ -11,12 +11,9 @@
 
 
 def check_admin_app(**kwargs):
-    from django.contrib.admin.sites import site
+    from django.contrib.admin.sites import system_check_errors
 
-    return list(chain.from_iterable(
-        model_admin.check(model, **kwargs)
-        for model, model_admin in site._registry.items()
-    ))
+    return system_check_errors
 
 
 class BaseModelAdminChecks(object):
diff -Nru python-django-1.7.1/django/contrib/admin/options.py python-django-1.7.3/django/contrib/admin/options.py
--- python-django-1.7.1/django/contrib/admin/options.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/admin/options.py	2015-01-13 19:28:00.000000000 +0100
@@ -139,7 +139,7 @@
         if cls.validator_class:
             warnings.warn(
                 'ModelAdmin.validator_class is deprecated. '
-                'ModeAdmin validators must be converted to use '
+                'ModelAdmin validators must be converted to use '
                 'the system check framework.',
                 RemovedInDjango19Warning)
             validator = cls.validator_class()
@@ -450,9 +450,9 @@
         except FieldDoesNotExist:
             return False
 
-        # Check whether this model is the origin of a M2M relationship
-        # in which case to_field has to be the pk on this model.
-        if opts.many_to_many and field.primary_key:
+        # Always allow referencing the primary key since it's already possible
+        # to get this information from the change view URL.
+        if field.primary_key:
             return True
 
         # Make sure at least one of the models registered for this site
@@ -463,8 +463,7 @@
             for inline in admin.inlines:
                 registered_models.add(inline.model)
 
-        for related_object in (opts.get_all_related_objects(include_hidden=True) +
-                               opts.get_all_related_many_to_many_objects()):
+        for related_object in opts.get_all_related_objects(include_hidden=True):
             related_model = related_object.model
             if (any(issubclass(model, related_model) for model in registered_models) and
                     related_object.field.rel.get_related_field() == field):
@@ -1400,7 +1399,7 @@
             else:
                 form_validated = False
                 new_object = form.instance
-            formsets, inline_instances = self._create_formsets(request, new_object)
+            formsets, inline_instances = self._create_formsets(request, new_object, change=not add)
             if all_valid(formsets) and form_validated:
                 self.save_model(request, new_object, form, not add)
                 self.save_related(request, form, formsets, not add)
@@ -1415,10 +1414,10 @@
             if add:
                 initial = self.get_changeform_initial_data(request)
                 form = ModelForm(initial=initial)
-                formsets, inline_instances = self._create_formsets(request, self.model())
+                formsets, inline_instances = self._create_formsets(request, self.model(), change=False)
             else:
                 form = ModelForm(instance=obj)
-                formsets, inline_instances = self._create_formsets(request, obj)
+                formsets, inline_instances = self._create_formsets(request, obj, change=True)
 
         adminForm = helpers.AdminForm(
             form,
@@ -1703,13 +1702,13 @@
             "admin/object_history.html"
         ], context, current_app=self.admin_site.name)
 
-    def _create_formsets(self, request, obj):
+    def _create_formsets(self, request, obj, change):
         "Helper function to generate formsets for add/change_view."
         formsets = []
         inline_instances = []
         prefixes = {}
         get_formsets_args = [request]
-        if obj.pk:
+        if change:
             get_formsets_args.append(obj)
         for FormSet, inline in self.get_formsets_with_inlines(*get_formsets_args):
             prefix = FormSet.get_default_prefix()
@@ -1830,6 +1829,8 @@
                 if self.cleaned_data.get(DELETION_FIELD_NAME, False):
                     using = router.db_for_write(self._meta.model)
                     collector = NestedObjects(using=using)
+                    if self.instance.pk is None:
+                        return
                     collector.collect([self.instance])
                     if collector.protected:
                         objs = []
diff -Nru python-django-1.7.1/django/contrib/admin/sites.py python-django-1.7.3/django/contrib/admin/sites.py
--- python-django-1.7.1/django/contrib/admin/sites.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/admin/sites.py	2015-01-13 19:28:00.000000000 +0100
@@ -14,6 +14,8 @@
 from django.views.decorators.cache import never_cache
 from django.conf import settings
 
+system_check_errors = []
+
 
 class AlreadyRegistered(Exception):
     pass
@@ -96,7 +98,7 @@
                     admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
 
                 if admin_class is not ModelAdmin and settings.DEBUG:
-                    admin_class.check(model)
+                    system_check_errors.extend(admin_class.check(model))
 
                 # Instantiate the admin class to save in the registry
                 self._registry[model] = admin_class(model, self)
diff -Nru python-django-1.7.1/django/contrib/admin/static/admin/js/SelectFilter2.js python-django-1.7.3/django/contrib/admin/static/admin/js/SelectFilter2.js
--- python-django-1.7.1/django/contrib/admin/static/admin/js/SelectFilter2.js	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/admin/static/admin/js/SelectFilter2.js	2015-01-13 19:28:00.000000000 +0100
@@ -15,7 +15,7 @@
 window.SelectFilter = {
     init: function(field_id, field_name, is_stacked, admin_static_prefix) {
         if (field_id.match(/__prefix__/)){
-            // Don't intialize on empty forms.
+            // Don't initialize on empty forms.
             return;
         }
         var from_box = document.getElementById(field_id);
diff -Nru python-django-1.7.1/django/contrib/admindocs/views.py python-django-1.7.3/django/contrib/admindocs/views.py
--- python-django-1.7.1/django/contrib/admindocs/views.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/admindocs/views.py	2015-01-13 19:28:00.000000000 +0100
@@ -309,6 +309,10 @@
     # Load/register all template tag libraries from installed apps.
     for module_name in template.get_templatetags_modules():
         mod = import_module(module_name)
+        if not hasattr(mod, '__file__'):
+            # e.g. packages installed as eggs
+            continue
+
         try:
             libraries = [
                 os.path.splitext(p)[0]
@@ -316,12 +320,13 @@
                 if p.endswith('.py') and p[0].isalpha()
             ]
         except OSError:
-            libraries = []
-        for library_name in libraries:
-            try:
-                template.get_library(library_name)
-            except template.InvalidTemplateLibrary:
-                pass
+            continue
+        else:
+            for library_name in libraries:
+                try:
+                    template.get_library(library_name)
+                except template.InvalidTemplateLibrary:
+                    pass
 
 
 def get_return_data_type(func_name):
diff -Nru python-django-1.7.1/django/contrib/auth/decorators.py python-django-1.7.3/django/contrib/auth/decorators.py
--- python-django-1.7.1/django/contrib/auth/decorators.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/auth/decorators.py	2015-01-13 19:28:05.000000000 +0100
@@ -3,7 +3,6 @@
 from django.contrib.auth import REDIRECT_FIELD_NAME
 from django.core.exceptions import PermissionDenied
 from django.utils.decorators import available_attrs
-from django.utils.encoding import force_str
 from django.utils.six.moves.urllib.parse import urlparse
 from django.shortcuts import resolve_url
 
@@ -21,9 +20,7 @@
             if test_func(request.user):
                 return view_func(request, *args, **kwargs)
             path = request.build_absolute_uri()
-            # urlparse chokes on lazy objects in Python 3, force to str
-            resolved_login_url = force_str(
-                resolve_url(login_url or settings.LOGIN_URL))
+            resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
             # If the login url is the same scheme and net location then just
             # use the path as the "next" url.
             login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
diff -Nru python-django-1.7.1/django/contrib/auth/hashers.py python-django-1.7.3/django/contrib/auth/hashers.py
--- python-django-1.7.1/django/contrib/auth/hashers.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/auth/hashers.py	2015-01-13 19:28:00.000000000 +0100
@@ -222,12 +222,12 @@
     """
     Secure password hashing using the PBKDF2 algorithm (recommended)
 
-    Configured to use PBKDF2 + HMAC + SHA256 with 12000 iterations.
+    Configured to use PBKDF2 + HMAC + SHA256 with 15000 iterations.
     The result is a 64 byte binary string.  Iterations may be changed
     safely but you must rename the algorithm if you change SHA256.
     """
     algorithm = "pbkdf2_sha256"
-    iterations = 12000
+    iterations = 15000
     digest = hashlib.sha256
 
     def encode(self, password, salt, iterations=None):
diff -Nru python-django-1.7.1/django/contrib/auth/__init__.py python-django-1.7.3/django/contrib/auth/__init__.py
--- python-django-1.7.1/django/contrib/auth/__init__.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/auth/__init__.py	2015-01-13 19:28:00.000000000 +0100
@@ -4,9 +4,10 @@
 from django.apps import apps as django_apps
 from django.conf import settings
 from django.core.exceptions import ImproperlyConfigured, PermissionDenied
+from django.middleware.csrf import rotate_token
+from django.utils.crypto import constant_time_compare
 from django.utils.module_loading import import_string
 from django.utils.translation import LANGUAGE_SESSION_KEY
-from django.middleware.csrf import rotate_token
 
 from .signals import user_logged_in, user_logged_out, user_login_failed
 
@@ -156,6 +157,18 @@
         if backend_path in settings.AUTHENTICATION_BACKENDS:
             backend = load_backend(backend_path)
             user = backend.get_user(user_id)
+            # Verify the session
+            if ('django.contrib.auth.middleware.SessionAuthenticationMiddleware'
+                    in settings.MIDDLEWARE_CLASSES and hasattr(user, 'get_session_auth_hash')):
+                session_hash = request.session.get(HASH_SESSION_KEY)
+                session_hash_verified = session_hash and constant_time_compare(
+                    session_hash,
+                    user.get_session_auth_hash()
+                )
+                if not session_hash_verified:
+                    request.session.flush()
+                    user = None
+
     return user or AnonymousUser()
 
 
diff -Nru python-django-1.7.1/django/contrib/auth/middleware.py python-django-1.7.3/django/contrib/auth/middleware.py
--- python-django-1.7.1/django/contrib/auth/middleware.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/auth/middleware.py	2015-01-06 02:20:47.000000000 +0100
@@ -2,7 +2,6 @@
 from django.contrib.auth import load_backend
 from django.contrib.auth.backends import RemoteUserBackend
 from django.core.exceptions import ImproperlyConfigured
-from django.utils.crypto import constant_time_compare
 from django.utils.functional import SimpleLazyObject
 
 
@@ -25,20 +24,15 @@
 
 class SessionAuthenticationMiddleware(object):
     """
-    Middleware for invalidating a user's sessions that don't correspond to the
-    user's current session authentication hash (generated based on the user's
-    password for AbstractUser).
+    Formerly, a middleware for invalidating a user's sessions that don't
+    correspond to the user's current session authentication hash. However, it
+    caused the "Vary: Cookie" header on all responses.
+
+    Now a backwards compatibility shim that enables session verification in
+    auth.get_user() if this middleware is in MIDDLEWARE_CLASSES.
     """
     def process_request(self, request):
-        user = request.user
-        if user and hasattr(user, 'get_session_auth_hash'):
-            session_hash = request.session.get(auth.HASH_SESSION_KEY)
-            session_hash_verified = session_hash and constant_time_compare(
-                session_hash,
-                user.get_session_auth_hash()
-            )
-            if not session_hash_verified:
-                auth.logout(request)
+        pass
 
 
 class RemoteUserMiddleware(object):
diff -Nru python-django-1.7.1/django/contrib/auth/tests/test_forms.py python-django-1.7.3/django/contrib/auth/tests/test_forms.py
--- python-django-1.7.1/django/contrib/auth/tests/test_forms.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/auth/tests/test_forms.py	2015-01-13 19:28:00.000000000 +0100
@@ -386,7 +386,7 @@
         self.assertFalse(form.is_valid())
         self.assertEqual(form['email'].errors, [_('Enter a valid email address.')])
 
-    def test_nonexistant_email(self):
+    def test_nonexistent_email(self):
         """
         Test nonexistent email address. This should not fail because it would
         expose information about registered users.
diff -Nru python-django-1.7.1/django/contrib/auth/tests/test_hashers.py python-django-1.7.3/django/contrib/auth/tests/test_hashers.py
--- python-django-1.7.1/django/contrib/auth/tests/test_hashers.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/auth/tests/test_hashers.py	2015-01-13 19:28:00.000000000 +0100
@@ -47,7 +47,7 @@
     def test_pkbdf2(self):
         encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
         self.assertEqual(encoded,
-            'pbkdf2_sha256$12000$seasalt$Ybw8zsFxqja97tY/o6G+Fy1ksY4U/Hw3DRrGED6Up4s=')
+            'pbkdf2_sha256$15000$seasalt$+qoFTwR4r71UCLMhmQUCou/LMu17XwQWfYIVd/xJ1RI=')
         self.assertTrue(is_password_usable(encoded))
         self.assertTrue(check_password('lètmein', encoded))
         self.assertFalse(check_password('lètmeinz', encoded))
@@ -211,14 +211,14 @@
         hasher = PBKDF2PasswordHasher()
         encoded = hasher.encode('lètmein', 'seasalt2')
         self.assertEqual(encoded,
-            'pbkdf2_sha256$12000$seasalt2$hlDLKsxgkgb1aeOppkM5atCYw5rPzAjCNQZ4NYyUROw=')
+            'pbkdf2_sha256$15000$seasalt2$uSQqI+91wgObKdP6L6S75LLzyxrZRWNcaujEZPA3/nA=')
         self.assertTrue(hasher.verify('lètmein', encoded))
 
     def test_low_level_pbkdf2_sha1(self):
         hasher = PBKDF2SHA1PasswordHasher()
         encoded = hasher.encode('lètmein', 'seasalt2')
         self.assertEqual(encoded,
-            'pbkdf2_sha1$12000$seasalt2$JeMRVfjjgtWw3/HzlnlfqBnQ6CA=')
+            'pbkdf2_sha1$15000$seasalt2$iYDXAPKgMsKMsarvA1MErD518Ug=')
         self.assertTrue(hasher.verify('lètmein', encoded))
 
     def test_upgrade(self):
diff -Nru python-django-1.7.1/django/contrib/auth/tests/test_middleware.py python-django-1.7.3/django/contrib/auth/tests/test_middleware.py
--- python-django-1.7.1/django/contrib/auth/tests/test_middleware.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/auth/tests/test_middleware.py	2015-01-13 19:28:00.000000000 +0100
@@ -1,4 +1,4 @@
-from django.contrib.auth.middleware import SessionAuthenticationMiddleware
+from django.contrib.auth.middleware import AuthenticationMiddleware
 from django.contrib.auth.models import User
 from django.http import HttpRequest
 from django.test import TestCase
@@ -11,25 +11,40 @@
                                              'test@example.com',
                                              self.user_password)
 
-    def test_changed_password_invalidates_session(self):
-        """
-        Tests that changing a user's password invalidates the session.
-        """
-        verification_middleware = SessionAuthenticationMiddleware()
+        self.middleware = AuthenticationMiddleware()
         self.assertTrue(self.client.login(
             username=self.user.username,
             password=self.user_password,
         ))
-        request = HttpRequest()
-        request.session = self.client.session
-        request.user = self.user
-        verification_middleware.process_request(request)
-        self.assertIsNotNone(request.user)
-        self.assertFalse(request.user.is_anonymous())
-
-        # After password change, user should be anonymous
-        request.user.set_password('new_password')
-        request.user.save()
-        verification_middleware.process_request(request)
-        self.assertIsNotNone(request.user)
-        self.assertTrue(request.user.is_anonymous())
+        self.request = HttpRequest()
+        self.request.session = self.client.session
+
+    def test_changed_password_doesnt_invalidate_session(self):
+        """
+        Changing a user's password shouldn't invalidate the session if session
+        verification isn't activated.
+        """
+        session_key = self.request.session.session_key
+        self.middleware.process_request(self.request)
+        self.assertIsNotNone(self.request.user)
+        self.assertFalse(self.request.user.is_anonymous())
+
+        # After password change, user should remain logged in.
+        self.user.set_password('new_password')
+        self.user.save()
+        self.middleware.process_request(self.request)
+        self.assertIsNotNone(self.request.user)
+        self.assertFalse(self.request.user.is_anonymous())
+        self.assertEqual(session_key, self.request.session.session_key)
+
+    def test_changed_password_invalidates_session_with_middleware(self):
+        session_key = self.request.session.session_key
+        with self.modify_settings(MIDDLEWARE_CLASSES={'append': ['django.contrib.auth.middleware.SessionAuthenticationMiddleware']}):
+            # After password change, user should be anonymous
+            self.user.set_password('new_password')
+            self.user.save()
+            self.middleware.process_request(self.request)
+            self.assertIsNotNone(self.request.user)
+            self.assertTrue(self.request.user.is_anonymous())
+        # session should be flushed
+        self.assertNotEqual(session_key, self.request.session.session_key)
diff -Nru python-django-1.7.1/django/contrib/auth/tests/test_views.py python-django-1.7.3/django/contrib/auth/tests/test_views.py
--- python-django-1.7.1/django/contrib/auth/tests/test_views.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/auth/tests/test_views.py	2015-01-13 19:28:05.000000000 +0100
@@ -1,3 +1,6 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
 from importlib import import_module
 import itertools
 import os
@@ -9,7 +12,7 @@
 from django.contrib.admin.models import LogEntry
 from django.contrib.auth.models import User
 from django.core import mail
-from django.core.urlresolvers import reverse, NoReverseMatch
+from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy
 from django.http import QueryDict, HttpRequest
 from django.utils.encoding import force_text
 from django.utils.http import urlquote
@@ -27,7 +30,7 @@
 # Needed so model is installed when tests are run independently:
 from django.contrib.auth.tests.custom_user import CustomUser  # NOQA
 from django.contrib.auth.tests.utils import skipIfCustomUser
-from django.contrib.auth.views import login as login_view
+from django.contrib.auth.views import login as login_view, redirect_to_login
 
 
 @override_settings(
@@ -652,6 +655,10 @@
         expected = 'http://remote.example.com/login/?next=%s' % quoted_next
         self.assertLoginURLEquals(expected)
 
+    @override_settings(LOGIN_URL=reverse_lazy('login'))
+    def test_lazy_login_url(self):
+        self.assertLoginURLEquals('/login/?next=/login_required/')
+
 
 @skipIfCustomUser
 class LoginRedirectUrlTest(AuthViewsTestCase):
@@ -677,6 +684,21 @@
         self.assertLoginRedirectURLEqual('http://remote.example.com/welcome/')
 
 
+class RedirectToLoginTests(AuthViewsTestCase):
+    """Tests for the redirect_to_login view"""
+    @override_settings(LOGIN_URL=reverse_lazy('login'))
+    def test_redirect_to_login_with_lazy(self):
+        login_redirect_response = redirect_to_login(next='/else/where/')
+        expected = '/login/?next=/else/where/'
+        self.assertEqual(expected, login_redirect_response.url)
+
+    @override_settings(LOGIN_URL=reverse_lazy('login'))
+    def test_redirect_to_login_with_lazy_and_unicode(self):
+        login_redirect_response = redirect_to_login(next='/else/where/झ/')
+        expected = '/login/?next=/else/where/%E0%A4%9D/'
+        self.assertEqual(expected, login_redirect_response.url)
+
+
 @skipIfCustomUser
 class LogoutTest(AuthViewsTestCase):
 
diff -Nru python-django-1.7.1/django/contrib/gis/db/backends/mysql/schema.py python-django-1.7.3/django/contrib/gis/db/backends/mysql/schema.py
--- python-django-1.7.1/django/contrib/gis/db/backends/mysql/schema.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/gis/db/backends/mysql/schema.py	2015-01-06 02:20:47.000000000 +0100
@@ -15,6 +15,13 @@
         super(MySQLGISSchemaEditor, self).__init__(*args, **kwargs)
         self.geometry_sql = []
 
+    def skip_default(self, field):
+        return (
+            super(MySQLGISSchemaEditor, self).skip_default(field) or
+            # Geometry fields are stored as BLOB/TEXT and can't have defaults.
+            isinstance(field, GeometryField)
+        )
+
     def column_sql(self, model, field, include_default=False):
         column_sql = super(MySQLGISSchemaEditor, self).column_sql(model, field, include_default)
         # MySQL doesn't support spatial indexes on NULL columns
diff -Nru python-django-1.7.1/django/contrib/gis/db/backends/spatialite/creation.py python-django-1.7.3/django/contrib/gis/db/backends/spatialite/creation.py
--- python-django-1.7.1/django/contrib/gis/db/backends/spatialite/creation.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/gis/db/backends/spatialite/creation.py	2015-01-13 19:28:00.000000000 +0100
@@ -95,7 +95,8 @@
             # InitSpatialMetaData() transparently creates the spatial metadata
             # tables
             cur = self.connection._cursor()
-            cur.execute("SELECT InitSpatialMetaData()")
+            arg = "1" if self.connection.ops.spatial_version >= (4, 1, 0) else ""
+            cur.execute("SELECT InitSpatialMetaData(%s)" % arg)
         else:
             # Spatialite < 2.4 -- Load the initial SQL
 
diff -Nru python-django-1.7.1/django/contrib/gis/db/models/fields.py python-django-1.7.3/django/contrib/gis/db/models/fields.py
--- python-django-1.7.1/django/contrib/gis/db/models/fields.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/gis/db/models/fields.py	2015-01-13 19:28:00.000000000 +0100
@@ -274,7 +274,7 @@
 
     def get_db_prep_save(self, value, connection):
         "Prepares the value for saving in the database."
-        if value is None:
+        if not value:
             return None
         else:
             return connection.ops.Adapter(self.get_prep_value(value))
diff -Nru python-django-1.7.1/django/contrib/gis/db/models/proxy.py python-django-1.7.3/django/contrib/gis/db/models/proxy.py
--- python-django-1.7.1/django/contrib/gis/db/models/proxy.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/gis/db/models/proxy.py	2015-01-13 19:28:00.000000000 +0100
@@ -57,7 +57,7 @@
             # Assigning the SRID to the geometry.
             if value.srid is None:
                 value.srid = self._field.srid
-        elif value is None or isinstance(value, six.string_types + (memoryview,)):
+        elif value is None or isinstance(value, six.string_types + (bytes, memoryview)):
             # Set with None, WKT, HEX, or WKB
             pass
         else:
diff -Nru python-django-1.7.1/django/contrib/gis/db/models/sql/query.py python-django-1.7.3/django/contrib/gis/db/models/sql/query.py
--- python-django-1.7.1/django/contrib/gis/db/models/sql/query.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/gis/db/models/sql/query.py	2015-01-13 19:28:00.000000000 +0100
@@ -14,7 +14,7 @@
     """
     A single spatial SQL query.
     """
-    # Overridding the valid query terms.
+    # Overriding the valid query terms.
     query_terms = ALL_TERMS
     aggregates_module = gis_aggregates
 
diff -Nru python-django-1.7.1/django/contrib/gis/gdal/srs.py python-django-1.7.3/django/contrib/gis/gdal/srs.py
--- python-django-1.7.1/django/contrib/gis/gdal/srs.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/gis/gdal/srs.py	2015-01-13 19:28:00.000000000 +0100
@@ -1,5 +1,5 @@
 """
-  The Spatial Reference class, represensents OGR Spatial Reference objects.
+  The Spatial Reference class, represents OGR Spatial Reference objects.
 
   Example:
   >>> from django.contrib.gis.gdal import SpatialReference
diff -Nru python-django-1.7.1/django/contrib/gis/tests/geoapp/tests.py python-django-1.7.3/django/contrib/gis/tests/geoapp/tests.py
--- python-django-1.7.1/django/contrib/gis/tests/geoapp/tests.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/gis/tests/geoapp/tests.py	2015-01-13 19:28:00.000000000 +0100
@@ -437,8 +437,11 @@
                 self.assertEqual(c.mpoly.difference(geom), c.difference)
                 if not spatialite:
                     self.assertEqual(c.mpoly.intersection(geom), c.intersection)
-                self.assertEqual(c.mpoly.sym_difference(geom), c.sym_difference)
-                self.assertEqual(c.mpoly.union(geom), c.union)
+                # Ordering might differ in collections
+                self.assertSetEqual(set(g.wkt for g in c.mpoly.sym_difference(geom)),
+                                    set(g.wkt for g in c.sym_difference))
+                self.assertSetEqual(set(g.wkt for g in c.mpoly.union(geom)),
+                                    set(g.wkt for g in c.union))
 
     @skipUnless(getattr(connection.ops, 'envelope', False), 'Database does not support envelope operation')
     def test_envelope(self):
@@ -781,9 +784,9 @@
     def test_unionagg(self):
         "Testing the `unionagg` (aggregate union) GeoQuerySet method."
         tx = Country.objects.get(name='Texas').mpoly
-        # Houston, Dallas -- Oracle has different order.
+        # Houston, Dallas -- Ordering may differ depending on backend or GEOS version.
         union1 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
-        union2 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
+        union2 = fromstr('MULTIPOINT(-95.363151 29.763374,-96.801611 32.782057)')
         qs = City.objects.filter(point__within=tx)
         self.assertRaises(TypeError, qs.unionagg, 'name')
         # Using `field_name` keyword argument in one query and specifying an
@@ -792,12 +795,8 @@
         u1 = qs.unionagg(field_name='point')
         u2 = qs.order_by('name').unionagg()
         tol = 0.00001
-        if oracle:
-            union = union2
-        else:
-            union = union1
-        self.assertEqual(True, union.equals_exact(u1, tol))
-        self.assertEqual(True, union.equals_exact(u2, tol))
+        self.assertEqual(True, union1.equals_exact(u1, tol) or union2.equals_exact(u1, tol))
+        self.assertEqual(True, union1.equals_exact(u2, tol) or union2.equals_exact(u2, tol))
         qs = City.objects.filter(name='NotACity')
         self.assertEqual(None, qs.unionagg(field_name='point'))
 
diff -Nru python-django-1.7.1/django/contrib/gis/tests/gis_migrations/test_operations.py python-django-1.7.3/django/contrib/gis/tests/gis_migrations/test_operations.py
--- python-django-1.7.1/django/contrib/gis/tests/gis_migrations/test_operations.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/gis/tests/gis_migrations/test_operations.py	2015-01-13 19:28:00.000000000 +0100
@@ -69,6 +69,7 @@
         Tests the AddField operation with a GIS-enabled column.
         """
         project_state = self.set_up_test_model()
+        self.current_state = project_state
         operation = migrations.AddField(
             "Neighborhood",
             "path",
@@ -90,11 +91,39 @@
                 indexes = connection.introspection.get_indexes(cursor, "gis_neighborhood")
             self.assertIn('path', indexes)
 
+    def test_add_blank_gis_field(self):
+        """
+        Should be able to add a GeometryField with blank=True.
+        """
+        project_state = self.set_up_test_model()
+        self.current_state = project_state
+        operation = migrations.AddField(
+            "Neighborhood",
+            "path",
+            fields.LineStringField(blank=True, srid=4326),
+        )
+        new_state = project_state.clone()
+        operation.state_forwards("gis", new_state)
+        with connection.schema_editor() as editor:
+            operation.database_forwards("gis", editor, project_state, new_state)
+        self.current_state = new_state
+        self.assertColumnExists("gis_neighborhood", "path")
+
+        # Test GeometryColumns when available
+        if HAS_GEOMETRY_COLUMNS:
+            self.assertGeometryColumnsCount(2)
+
+        if self.has_spatial_indexes:
+            with connection.cursor() as cursor:
+                indexes = connection.introspection.get_indexes(cursor, "gis_neighborhood")
+            self.assertIn('path', indexes)
+
     def test_remove_gis_field(self):
         """
         Tests the RemoveField operation with a GIS-enabled column.
         """
         project_state = self.set_up_test_model()
+        self.current_state = project_state
         operation = migrations.RemoveField("Neighborhood", "geom")
         new_state = project_state.clone()
         operation.state_forwards("gis", new_state)
diff -Nru python-django-1.7.1/django/contrib/sites/management.py python-django-1.7.3/django/contrib/sites/management.py
--- python-django-1.7.1/django/contrib/sites/management.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/sites/management.py	2015-01-13 19:28:01.000000000 +0100
@@ -8,13 +8,13 @@
 from django.db.models import signals
 
 
-def create_default_site(app_config, verbosity=2, interactive=True, db=DEFAULT_DB_ALIAS, **kwargs):
+def create_default_site(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs):
     try:
         Site = apps.get_model('sites', 'Site')
     except LookupError:
         return
 
-    if not router.allow_migrate(db, Site):
+    if not router.allow_migrate(using, Site):
         return
 
     if not Site.objects.exists():
@@ -25,15 +25,15 @@
         # can also crop up outside of tests - see #15346.
         if verbosity >= 2:
             print("Creating example.com Site object")
-        Site(pk=1, domain="example.com", name="example.com").save(using=db)
+        Site(pk=1, domain="example.com", name="example.com").save(using=using)
 
         # We set an explicit pk instead of relying on auto-incrementation,
         # so we need to reset the database sequence. See #17415.
-        sequence_sql = connections[db].ops.sequence_reset_sql(no_style(), [Site])
+        sequence_sql = connections[using].ops.sequence_reset_sql(no_style(), [Site])
         if sequence_sql:
             if verbosity >= 2:
                 print("Resetting sequence")
-            with connections[db].cursor() as cursor:
+            with connections[using].cursor() as cursor:
                 for command in sequence_sql:
                     cursor.execute(command)
 
diff -Nru python-django-1.7.1/django/contrib/sites/tests.py python-django-1.7.3/django/contrib/sites/tests.py
--- python-django-1.7.1/django/contrib/sites/tests.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/sites/tests.py	2015-01-13 19:28:01.000000000 +0100
@@ -1,10 +1,13 @@
 from __future__ import unicode_literals
 
+from django.apps import apps
 from django.conf import settings
 from django.core.exceptions import ObjectDoesNotExist, ValidationError
+from django.db import router
 from django.http import HttpRequest
 from django.test import TestCase, modify_settings, override_settings
 
+from .management import create_default_site
 from .middleware import CurrentSiteMiddleware
 from .models import Site
 from .requests import RequestSite
@@ -17,12 +20,6 @@
     def setUp(self):
         Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
 
-    def test_save_another(self):
-        # Regression for #17415
-        # On some backends the sequence needs reset after save with explicit ID.
-        # Test that there is no sequence collisions by saving another site.
-        Site(domain="example2.com", name="example2.com").save()
-
     def test_site_manager(self):
         # Make sure that get_current() does not return a deleted Site object.
         s = Site.objects.get_current()
@@ -82,6 +79,58 @@
         self.assertRaises(ValidationError, site.full_clean)
 
 
+class JustOtherRouter(object):
+    def allow_migrate(self, db, model):
+        return db == 'other'
+
+
+@modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
+class CreateDefaultSiteTests(TestCase):
+    multi_db = True
+
+    def setUp(self):
+        self.app_config = apps.get_app_config('sites')
+        # Delete the site created as part of the default migration process.
+        Site.objects.all().delete()
+
+    def test_basic(self):
+        """
+        #15346, #15573 - create_default_site() creates an example site only if
+        none exist.
+        """
+        create_default_site(self.app_config, verbosity=0)
+        self.assertEqual(Site.objects.count(), 1)
+
+        create_default_site(self.app_config, verbosity=0)
+        self.assertEqual(Site.objects.count(), 1)
+
+    def test_multi_db(self):
+        """
+        #16353, #16828 - The default site creation should respect db routing.
+        """
+        old_routers = router.routers
+        router.routers = [JustOtherRouter()]
+        try:
+            create_default_site(self.app_config, using='default', verbosity=0)
+            create_default_site(self.app_config, using='other', verbosity=0)
+            self.assertFalse(Site.objects.using('default').exists())
+            self.assertTrue(Site.objects.using('other').exists())
+        finally:
+            router.routers = old_routers
+
+    def test_save_another(self):
+        """
+        #17415 - Another site can be created right after the default one.
+
+        On some backends the sequence needs to be reset after saving with an
+        explicit ID. Test that there isn't a sequence collisions by saving
+        another site. This test is only meaningful with databases that use
+        sequences for automatic primary keys such as PostgreSQL and Oracle.
+        """
+        create_default_site(self.app_config, verbosity=0)
+        Site(domain='example2.com', name='example2.com').save()
+
+
 class MiddlewareTest(TestCase):
 
     def test_request(self):
diff -Nru python-django-1.7.1/django/contrib/webdesign/tests.py python-django-1.7.3/django/contrib/webdesign/tests.py
--- python-django-1.7.1/django/contrib/webdesign/tests.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/contrib/webdesign/tests.py	2015-01-13 19:28:01.000000000 +0100
@@ -4,7 +4,7 @@
 import unittest
 
 from django.contrib.webdesign.lorem_ipsum import paragraphs, words
-from django.template import loader, Context
+from django.template import Context, Template
 
 
 class WebdesignTest(unittest.TestCase):
@@ -17,6 +17,6 @@
                          ['Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'])
 
     def test_lorem_tag(self):
-        t = loader.get_template_from_string("{% load webdesign %}{% lorem 3 w %}")
+        t = Template("{% load webdesign %}{% lorem 3 w %}")
         self.assertEqual(t.render(Context({})),
                          'lorem ipsum dolor')
diff -Nru python-django-1.7.1/django/core/exceptions.py python-django-1.7.3/django/core/exceptions.py
--- python-django-1.7.1/django/core/exceptions.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/exceptions.py	2015-01-13 19:28:01.000000000 +0100
@@ -118,7 +118,10 @@
                 # Normalize plain strings to instances of ValidationError.
                 if not isinstance(message, ValidationError):
                     message = ValidationError(message)
-                self.error_list.extend(message.error_list)
+                if hasattr(message, 'error_dict'):
+                    self.error_list.extend(sum(message.error_dict.values(), []))
+                else:
+                    self.error_list.extend(message.error_list)
 
         else:
             self.message = message
diff -Nru python-django-1.7.1/django/core/files/base.py python-django-1.7.3/django/core/files/base.py
--- python-django-1.7.1/django/core/files/base.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/files/base.py	2015-01-13 19:28:01.000000000 +0100
@@ -3,10 +3,11 @@
 import os
 from io import BytesIO, StringIO, UnsupportedOperation
 
-from django.utils.encoding import smart_text
 from django.core.files.utils import FileProxyMixin
 from django.utils import six
-from django.utils.encoding import force_bytes, python_2_unicode_compatible
+from django.utils.encoding import (
+    force_bytes, force_str, python_2_unicode_compatible, smart_text,
+)
 
 
 @python_2_unicode_compatible
@@ -25,7 +26,7 @@
         return smart_text(self.name or '')
 
     def __repr__(self):
-        return "<%s: %s>" % (self.__class__.__name__, self or "None")
+        return force_str("<%s: %s>" % (self.__class__.__name__, self or "None"))
 
     def __bool__(self):
         return bool(self.name)
diff -Nru python-django-1.7.1/django/core/management/commands/flush.py python-django-1.7.3/django/core/management/commands/flush.py
--- python-django-1.7.1/django/core/management/commands/flush.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/management/commands/flush.py	2015-01-13 19:28:01.000000000 +0100
@@ -84,9 +84,13 @@
 
             # Reinstall the initial_data fixture.
             if options.get('load_initial_data'):
-                # Reinstall the initial_data fixture.
-                call_command('loaddata', 'initial_data', **options)
-
+                # Reinstall the initial_data fixture for apps without migrations.
+                from django.db.migrations.executor import MigrationExecutor
+                executor = MigrationExecutor(connection)
+                app_options = options.copy()
+                for app_label in executor.loader.unmigrated_apps:
+                    app_options['app_label'] = app_label
+                    call_command('loaddata', 'initial_data', **app_options)
         else:
             self.stdout.write("Flush cancelled.\n")
 
diff -Nru python-django-1.7.1/django/core/management/commands/makemessages.py python-django-1.7.3/django/core/management/commands/makemessages.py
--- python-django-1.7.1/django/core/management/commands/makemessages.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/management/commands/makemessages.py	2015-01-13 19:28:01.000000000 +0100
@@ -355,7 +355,7 @@
                 norm_patterns.append(p)
 
         all_files = []
-        ignored_roots = [os.path.normpath(p) for p in (settings.MEDIA_ROOT, settings.STATIC_ROOT)]
+        ignored_roots = [os.path.normpath(p) for p in (settings.MEDIA_ROOT, settings.STATIC_ROOT) if p]
         for dirpath, dirnames, filenames in os.walk(force_text(root), topdown=True, followlinks=self.symlinks):
             for dirname in dirnames[:]:
                 if (is_ignored(os.path.normpath(os.path.join(dirpath, dirname)), norm_patterns) or
diff -Nru python-django-1.7.1/django/core/management/commands/migrate.py python-django-1.7.3/django/core/management/commands/migrate.py
--- python-django-1.7.1/django/core/management/commands/migrate.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/management/commands/migrate.py	2015-01-13 19:28:01.000000000 +0100
@@ -128,6 +128,7 @@
             created_models = self.sync_apps(connection, executor.loader.unmigrated_apps)
         else:
             created_models = []
+            emit_pre_migrate_signal([], self.verbosity, self.interactive, connection.alias)
 
         # The test runner requires us to flush after a syncdb but before migrations,
         # so do that here.
@@ -304,7 +305,7 @@
         some named apps.
         """
         # Load migrations from disk/DB
-        loader = MigrationLoader(connection)
+        loader = MigrationLoader(connection, ignore_no_migrations=True)
         graph = loader.graph
         # If we were passed a list of apps, validate it
         if app_names:
diff -Nru python-django-1.7.1/django/core/management/commands/runserver.py python-django-1.7.3/django/core/management/commands/runserver.py
--- python-django-1.7.1/django/core/management/commands/runserver.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/management/commands/runserver.py	2015-01-13 19:28:01.000000000 +0100
@@ -13,7 +13,7 @@
 from django.db import connections, DEFAULT_DB_ALIAS
 from django.db.migrations.executor import MigrationExecutor
 from django.utils import autoreload
-from django.utils.encoding import get_system_encoding
+from django.utils.encoding import force_text, get_system_encoding
 from django.utils import six
 from django.core.exceptions import ImproperlyConfigured
 
@@ -142,7 +142,7 @@
             try:
                 error_text = ERRORS[e.errno]
             except KeyError:
-                error_text = str(e)
+                error_text = force_text(e)
             self.stderr.write("Error: %s" % error_text)
             # Need to use an OS exit because sys.exit doesn't work in a thread
             os._exit(1)
diff -Nru python-django-1.7.1/django/core/management/commands/sqlsequencereset.py python-django-1.7.3/django/core/management/commands/sqlsequencereset.py
--- python-django-1.7.1/django/core/management/commands/sqlsequencereset.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/management/commands/sqlsequencereset.py	2015-01-13 19:28:01.000000000 +0100
@@ -3,7 +3,6 @@
 from optparse import make_option
 
 from django.core.management.base import AppCommand
-from django.core.management.sql import check_for_migrations
 from django.db import connections, DEFAULT_DB_ALIAS
 
 
@@ -23,7 +22,6 @@
         if app_config.models_module is None:
             return
         connection = connections[options.get('database')]
-        check_for_migrations(app_config, connection)
         models = app_config.get_models(include_auto_created=True)
         statements = connection.ops.sequence_reset_sql(self.style, models)
         return '\n'.join(statements)
diff -Nru python-django-1.7.1/django/core/management/commands/squashmigrations.py python-django-1.7.3/django/core/management/commands/squashmigrations.py
--- python-django-1.7.1/django/core/management/commands/squashmigrations.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/management/commands/squashmigrations.py	2015-01-13 19:28:01.000000000 +0100
@@ -24,7 +24,7 @@
     usage_str = "Usage: ./manage.py squashmigrations app migration_name"
     args = "app_label migration_name"
 
-    def handle(self, app_label=None, migration_name=None, **options):
+    def handle(self, app_label=None, migration_name=None, no_optimize=None, **options):
 
         self.verbosity = int(options.get('verbosity'))
         self.interactive = options.get('interactive')
@@ -87,17 +87,25 @@
                 elif dependency[0] != smigration.app_label:
                     dependencies.add(dependency)
 
-        if self.verbosity > 0:
-            self.stdout.write(self.style.MIGRATE_HEADING("Optimizing..."))
-
-        optimizer = MigrationOptimizer()
-        new_operations = optimizer.optimize(operations, migration.app_label)
-
-        if self.verbosity > 0:
-            if len(new_operations) == len(operations):
-                self.stdout.write("  No optimizations possible.")
-            else:
-                self.stdout.write("  Optimized from %s operations to %s operations." % (len(operations), len(new_operations)))
+        if no_optimize:
+            if self.verbosity > 0:
+                self.stdout.write(self.style.MIGRATE_HEADING("(Skipping optimization.)"))
+            new_operations = operations
+        else:
+            if self.verbosity > 0:
+                self.stdout.write(self.style.MIGRATE_HEADING("Optimizing..."))
+
+            optimizer = MigrationOptimizer()
+            new_operations = optimizer.optimize(operations, migration.app_label)
+
+            if self.verbosity > 0:
+                if len(new_operations) == len(operations):
+                    self.stdout.write("  No optimizations possible.")
+                else:
+                    self.stdout.write(
+                        "  Optimized from %s operations to %s operations." %
+                        (len(operations), len(new_operations))
+                    )
 
         # Work out the value of replaces (any squashed ones we're re-squashing)
         # need to feed their replaces into ours
diff -Nru python-django-1.7.1/django/core/serializers/xml_serializer.py python-django-1.7.3/django/core/serializers/xml_serializer.py
--- python-django-1.7.1/django/core/serializers/xml_serializer.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/serializers/xml_serializer.py	2015-01-13 19:28:01.000000000 +0100
@@ -187,7 +187,7 @@
         m2m_data = {}
 
         model_fields = Model._meta.get_all_field_names()
-        # Deseralize each field.
+        # Deserialize each field.
         for field_node in node.getElementsByTagName("field"):
             # If the field is missing the name attribute, bail (are you
             # sensing a pattern here?)
diff -Nru python-django-1.7.1/django/core/servers/basehttp.py python-django-1.7.3/django/core/servers/basehttp.py
--- python-django-1.7.1/django/core/servers/basehttp.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/core/servers/basehttp.py	2015-01-13 19:28:05.000000000 +0100
@@ -155,6 +155,17 @@
 
         sys.stderr.write(msg)
 
+    def get_environ(self):
+        # Strip all headers with underscores in the name before constructing
+        # the WSGI environ. This prevents header-spoofing based on ambiguity
+        # between underscores and dashes both normalized to underscores in WSGI
+        # env vars. Nginx and Apache 2.4+ both do this as well.
+        for k, v in self.headers.items():
+            if '_' in k:
+                del self.headers[k]
+
+        return super(WSGIRequestHandler, self).get_environ()
+
 
 def run(addr, port, wsgi_handler, ipv6=False, threading=False):
     server_address = (addr, port)
diff -Nru python-django-1.7.1/django/db/backends/mysql/base.py python-django-1.7.3/django/db/backends/mysql/base.py
--- python-django-1.7.1/django/db/backends/mysql/base.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/backends/mysql/base.py	2015-01-13 19:28:01.000000000 +0100
@@ -1,7 +1,8 @@
 """
 MySQL database backend for Django.
 
-Requires MySQLdb: http://sourceforge.net/projects/mysql-python
+Requires mysqlclient: https://pypi.python.org/pypi/mysqlclient/
+MySQLdb is supported for Python 2 only: http://sourceforge.net/projects/mysql-python
 """
 from __future__ import unicode_literals
 
diff -Nru python-django-1.7.1/django/db/backends/mysql/validation.py python-django-1.7.3/django/db/backends/mysql/validation.py
--- python-django-1.7.1/django/db/backends/mysql/validation.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/backends/mysql/validation.py	2015-01-06 02:20:47.000000000 +0100
@@ -17,6 +17,10 @@
         if getattr(field, 'rel', None) is None:
             field_type = field.db_type(connection)
 
+            # Ignore any non-concrete fields
+            if field_type is None:
+                return errors
+
             if (field_type.startswith('varchar')  # Look for CharFields...
                     and field.unique  # ... that are unique
                     and (field.max_length is None or int(field.max_length) > 255)):
diff -Nru python-django-1.7.1/django/db/backends/oracle/creation.py python-django-1.7.3/django/db/backends/oracle/creation.py
--- python-django-1.7.1/django/db/backends/oracle/creation.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/backends/oracle/creation.py	2015-01-13 19:28:01.000000000 +0100
@@ -216,11 +216,11 @@
         statements = [
             """CREATE TABLESPACE %(tblspace)s
                DATAFILE '%(tblspace)s.dbf' SIZE 20M
-               REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 200M
+               REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 300M
             """,
             """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s
                TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M
-               REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M
+               REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 150M
             """,
         ]
         self._execute_statements(cursor, statements, parameters, verbosity)
diff -Nru python-django-1.7.1/django/db/backends/postgresql_psycopg2/schema.py python-django-1.7.3/django/db/backends/postgresql_psycopg2/schema.py
--- python-django-1.7.1/django/db/backends/postgresql_psycopg2/schema.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/backends/postgresql_psycopg2/schema.py	2015-01-06 02:20:47.000000000 +0100
@@ -6,12 +6,34 @@
     sql_create_sequence = "CREATE SEQUENCE %(sequence)s"
     sql_delete_sequence = "DROP SEQUENCE IF EXISTS %(sequence)s CASCADE"
     sql_set_sequence_max = "SELECT setval('%(sequence)s', MAX(%(column)s)) FROM %(table)s"
+    sql_create_varchar_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s varchar_pattern_ops)%(extra)s"
+    sql_create_text_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s text_pattern_ops)%(extra)s"
 
     def quote_value(self, value):
         # Inner import so backend fails nicely if it's not present
         import psycopg2
         return psycopg2.extensions.adapt(value)
 
+    def _model_indexes_sql(self, model):
+        output = super(DatabaseSchemaEditor, self)._model_indexes_sql(model)
+        if not model._meta.managed or model._meta.proxy or model._meta.swapped:
+            return output
+
+        for field in model._meta.local_fields:
+            db_type = field.db_type(connection=self.connection)
+            if db_type is not None and (field.db_index or field.unique):
+                # Fields with database column types of `varchar` and `text` need
+                # a second index that specifies their operator class, which is
+                # needed when performing correct LIKE queries outside the
+                # C locale. See #12234.
+                if db_type.startswith('varchar'):
+                    output.append(self._create_index_sql(
+                        model, [field], suffix='_like', sql=self.sql_create_varchar_index))
+                elif db_type.startswith('text'):
+                    output.append(self._create_index_sql(
+                        model, [field], suffix='_like', sql=self.sql_create_text_index))
+        return output
+
     def _alter_column_type_sql(self, table, column, type):
         """
         Makes ALTER TYPE with SERIAL make sense.
diff -Nru python-django-1.7.1/django/db/backends/schema.py python-django-1.7.3/django/db/backends/schema.py
--- python-django-1.7.1/django/db/backends/schema.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/backends/schema.py	2015-01-13 19:28:01.000000000 +0100
@@ -93,7 +93,11 @@
         # Log the command we're running, then run it
         logger.debug("%s; (params %r)" % (sql, params))
         if self.collect_sql:
-            self.collected_sql.append((sql % tuple(map(self.quote_value, params))) + ";")
+            ending = "" if sql.endswith(";") else ";"
+            if params is not None:
+                self.collected_sql.append((sql % tuple(map(self.quote_value, params))) + ending)
+            else:
+                self.collected_sql.append(sql + ending)
         else:
             with self.connection.cursor() as cursor:
                 cursor.execute(sql, params)
@@ -218,16 +222,6 @@
             if col_type_suffix:
                 definition += " %s" % col_type_suffix
             params.extend(extra_params)
-            # Indexes
-            if field.db_index and not field.unique:
-                self.deferred_sql.append(
-                    self.sql_create_index % {
-                        "name": self._create_index_name(model, [field.column], suffix=""),
-                        "table": self.quote_name(model._meta.db_table),
-                        "columns": self.quote_name(field.column),
-                        "extra": "",
-                    }
-                )
             # FK
             if field.rel and field.db_constraint:
                 to_table = field.rel.to._meta.db_table
@@ -260,16 +254,16 @@
             "table": self.quote_name(model._meta.db_table),
             "definition": ", ".join(column_sqls)
         }
+        if model._meta.db_tablespace:
+            tablespace_sql = self.connection.ops.tablespace_sql(model._meta.db_tablespace)
+            if tablespace_sql:
+                sql += ' ' + tablespace_sql
+
         self.execute(sql, params)
-        # Add any index_togethers
-        for fields in model._meta.index_together:
-            columns = [model._meta.get_field_by_name(field)[0].column for field in fields]
-            self.execute(self.sql_create_index % {
-                "table": self.quote_name(model._meta.db_table),
-                "name": self._create_index_name(model, columns, suffix="_idx"),
-                "columns": ", ".join(self.quote_name(column) for column in columns),
-                "extra": "",
-            })
+
+        # Add any field index and index_together's (deferred as SQLite3 _remake_table needs it)
+        self.deferred_sql.extend(self._model_indexes_sql(model))
+
         # Make M2M tables
         for field in model._meta.local_many_to_many:
             if field.rel.through._meta.auto_created:
@@ -333,14 +327,9 @@
                 ))
             self.execute(self._delete_constraint_sql(self.sql_delete_index, model, constraint_names[0]))
         # Created indexes
-        for fields in news.difference(olds):
-            columns = [model._meta.get_field_by_name(field)[0].column for field in fields]
-            self.execute(self.sql_create_index % {
-                "table": self.quote_name(model._meta.db_table),
-                "name": self._create_index_name(model, columns, suffix="_idx"),
-                "columns": ", ".join(self.quote_name(column) for column in columns),
-                "extra": "",
-            })
+        for field_names in news.difference(olds):
+            fields = [model._meta.get_field_by_name(field)[0] for field in field_names]
+            self.execute(self._create_index_sql(model, fields, suffix="_idx"))
 
     def alter_db_table(self, model, old_db_table, new_db_table):
         """
@@ -400,14 +389,7 @@
             self.execute(sql)
         # Add an index, if required
         if field.db_index and not field.unique:
-            self.deferred_sql.append(
-                self.sql_create_index % {
-                    "name": self._create_index_name(model, [field.column], suffix=""),
-                    "table": self.quote_name(model._meta.db_table),
-                    "columns": self.quote_name(field.column),
-                    "extra": "",
-                }
-            )
+            self.deferred_sql.append(self._create_index_sql(model, [field]))
         # Add any FK constraints later
         if field.rel and self.connection.features.supports_foreign_keys and field.db_constraint:
             self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
@@ -507,16 +489,12 @@
                 rel_fk_names = self._constraint_names(rel.model, [rel.field.column], foreign_key=True)
                 for fk_name in rel_fk_names:
                     self.execute(self._delete_constraint_sql(self.sql_delete_fk, rel.model, fk_name))
-        # Removed an index?
-        if old_field.db_index and not new_field.db_index and not old_field.unique and not (not new_field.unique and old_field.unique):
+        # Removed an index? (no strict check, as multiple indexes are possible)
+        if (old_field.db_index and not new_field.db_index and
+                not old_field.unique and not
+                (not new_field.unique and old_field.unique)):
             # Find the index for this field
             index_names = self._constraint_names(model, [old_field.column], index=True)
-            if strict and len(index_names) != 1:
-                raise ValueError("Found wrong number (%s) of indexes for %s.%s" % (
-                    len(index_names),
-                    model._meta.db_table,
-                    old_field.column,
-                ))
             for index_name in index_names:
                 self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
         # Change check constraints?
@@ -556,34 +534,31 @@
         # Default change?
         old_default = self.effective_default(old_field)
         new_default = self.effective_default(new_field)
-        if old_default != new_default:
-            if new_default is None:
+        needs_database_default = (
+            old_default != new_default and
+            new_default is not None and
+            not self.skip_default(new_field)
+        )
+        if needs_database_default:
+            if self.connection.features.requires_literal_defaults:
+                # Some databases can't take defaults as a parameter (oracle)
+                # If this is the case, the individual schema backend should
+                # implement prepare_default
                 actions.append((
-                    self.sql_alter_column_no_default % {
+                    self.sql_alter_column_default % {
                         "column": self.quote_name(new_field.column),
+                        "default": self.prepare_default(new_default),
                     },
                     [],
                 ))
             else:
-                if self.connection.features.requires_literal_defaults:
-                    # Some databases can't take defaults as a parameter (oracle)
-                    # If this is the case, the individual schema backend should
-                    # implement prepare_default
-                    actions.append((
-                        self.sql_alter_column_default % {
-                            "column": self.quote_name(new_field.column),
-                            "default": self.prepare_default(new_default),
-                        },
-                        [],
-                    ))
-                else:
-                    actions.append((
-                        self.sql_alter_column_default % {
-                            "column": self.quote_name(new_field.column),
-                            "default": "%s",
-                        },
-                        [new_default],
-                    ))
+                actions.append((
+                    self.sql_alter_column_default % {
+                        "column": self.quote_name(new_field.column),
+                        "default": "%s",
+                    },
+                    [new_default],
+                ))
         # Nullability change?
         if old_field.null != new_field.null:
             if new_field.null:
@@ -613,7 +588,7 @@
                 # directly run a (NOT) NULL alteration
                 actions = actions + null_actions
             # Combine actions together if we can (e.g. postgres)
-            if self.connection.features.supports_combined_alters:
+            if self.connection.features.supports_combined_alters and actions:
                 sql, params = tuple(zip(*actions))
                 actions = [(", ".join(sql), reduce(operator.add, params))]
             # Apply those actions
@@ -652,15 +627,10 @@
         if not old_field.unique and new_field.unique:
             self.execute(self._create_unique_sql(model, [new_field.column]))
         # Added an index?
-        if not old_field.db_index and new_field.db_index and not new_field.unique and not (not old_field.unique and new_field.unique):
-            self.execute(
-                self.sql_create_index % {
-                    "table": self.quote_name(model._meta.db_table),
-                    "name": self._create_index_name(model, [new_field.column], suffix="_uniq"),
-                    "columns": self.quote_name(new_field.column),
-                    "extra": "",
-                }
-            )
+        if (not old_field.db_index and new_field.db_index and
+                not new_field.unique and not
+                (not old_field.unique and new_field.unique)):
+            self.execute(self._create_index_sql(model, [new_field], suffix="_uniq"))
         # Type alteration on primary key? Then we need to alter the column
         # referring to us.
         rels_to_update = []
@@ -723,7 +693,7 @@
             )
         # Drop the default if we need to
         # (Django usually does not use in-database defaults)
-        if not self.skip_default(new_field) and new_field.default is not None:
+        if needs_database_default:
             sql = self.sql_alter_column % {
                 "table": self.quote_name(model._meta.db_table),
                 "changes": self.sql_alter_column_no_default % {
@@ -808,15 +778,47 @@
             index_name = "D%s" % index_name[:-1]
         return index_name
 
-    def _create_index_sql(self, model, fields, suffix=""):
+    def _create_index_sql(self, model, fields, suffix="", sql=None):
+        """
+        Return the SQL statement to create the index for one or several fields.
+        `sql` can be specified if the syntax differs from the standard (GIS
+        indexes, ...).
+        """
+        if len(fields) == 1 and fields[0].db_tablespace:
+            tablespace_sql = self.connection.ops.tablespace_sql(fields[0].db_tablespace)
+        elif model._meta.db_tablespace:
+            tablespace_sql = self.connection.ops.tablespace_sql(model._meta.db_tablespace)
+        else:
+            tablespace_sql = ""
+        if tablespace_sql:
+            tablespace_sql = " " + tablespace_sql
+
         columns = [field.column for field in fields]
-        return self.sql_create_index % {
+        sql_create_index = sql or self.sql_create_index
+        return sql_create_index % {
             "table": self.quote_name(model._meta.db_table),
             "name": self.quote_name(self._create_index_name(model, columns, suffix=suffix)),
             "columns": ", ".join(self.quote_name(column) for column in columns),
-            "extra": "",
+            "extra": tablespace_sql,
         }
 
+    def _model_indexes_sql(self, model):
+        """
+        Return all index SQL statements (field indexes, index_together) for the
+        specified model, as a list.
+        """
+        if not model._meta.managed or model._meta.proxy or model._meta.swapped:
+            return []
+        output = []
+        for field in model._meta.local_fields:
+            if field.db_index and not field.unique:
+                output.append(self._create_index_sql(model, [field], suffix=""))
+
+        for field_names in model._meta.index_together:
+            fields = [model._meta.get_field_by_name(field)[0] for field in field_names]
+            output.append(self._create_index_sql(model, fields, suffix="_idx"))
+        return output
+
     def _create_fk_sql(self, model, field, suffix):
         from_table = model._meta.db_table
         from_column = field.column
diff -Nru python-django-1.7.1/django/db/backends/sqlite3/schema.py python-django-1.7.3/django/db/backends/sqlite3/schema.py
--- python-django-1.7.1/django/db/backends/sqlite3/schema.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/backends/sqlite3/schema.py	2015-01-13 19:28:01.000000000 +0100
@@ -43,7 +43,8 @@
         else:
             raise ValueError("Cannot quote parameter value %r of type %s" % (value, type(value)))
 
-    def _remake_table(self, model, create_fields=[], delete_fields=[], alter_fields=[], override_uniques=None):
+    def _remake_table(self, model, create_fields=[], delete_fields=[], alter_fields=[], override_uniques=None,
+                      override_indexes=None):
         """
         Shortcut to transform a model from old_model into new_model
         """
@@ -68,15 +69,15 @@
         # Add in any created fields
         for field in create_fields:
             body[field.name] = field
-            # If there's a default, insert it into the copy map
-            if field.has_default():
+            # Choose a default and insert it into the copy map
+            if not isinstance(field, ManyToManyField):
                 mapping[field.column] = self.quote_value(
                     self.effective_default(field)
                 )
         # Add in any altered fields
         for (old_field, new_field) in alter_fields:
-            del body[old_field.name]
-            del mapping[old_field.column]
+            body.pop(old_field.name, None)
+            mapping.pop(old_field.column, None)
             body[new_field.name] = new_field
             if old_field.null and not new_field.null:
                 case_sql = "coalesce(%(col)s, %(default)s)" % {
@@ -110,11 +111,20 @@
                 for unique in model._meta.unique_together
             ]
 
+        # Work out the new value for index_together, taking renames into
+        # account
+        if override_indexes is None:
+            override_indexes = [
+                [rename_mapping.get(n, n) for n in index]
+                for index in model._meta.index_together
+            ]
+
         # Construct a new model for the new state
         meta_contents = {
             'app_label': model._meta.app_label,
             'db_table': model._meta.db_table + "__new",
             'unique_together': override_uniques,
+            'index_together': override_indexes,
             'apps': apps,
         }
         meta = type("Meta", tuple(), meta_contents)
@@ -189,6 +199,14 @@
         # Alter by remaking table
         self._remake_table(model, alter_fields=[(old_field, new_field)])
 
+    def alter_index_together(self, model, old_index_together, new_index_together):
+        """
+        Deals with a model changing its index_together.
+        Note: The input index_togethers must be doubly-nested, not the single-
+        nested ["foo", "bar"] format.
+        """
+        self._remake_table(model, override_indexes=new_index_together)
+
     def alter_unique_together(self, model, old_unique_together, new_unique_together):
         """
         Deals with a model changing its unique_together.
diff -Nru python-django-1.7.1/django/db/migrations/autodetector.py python-django-1.7.3/django/db/migrations/autodetector.py
--- python-django-1.7.1/django/db/migrations/autodetector.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/autodetector.py	2015-01-13 19:28:01.000000000 +0100
@@ -162,7 +162,8 @@
             old_model_state = self.from_state.models[app_label, old_model_name]
             for field_name, field in old_model_state.fields:
                 old_field = self.old_apps.get_model(app_label, old_model_name)._meta.get_field_by_name(field_name)[0]
-                if hasattr(old_field, "rel") and getattr(old_field.rel, "through", None) and not old_field.rel.through._meta.auto_created:
+                if (hasattr(old_field, "rel") and getattr(old_field.rel, "through", None)
+                        and not old_field.rel.through._meta.auto_created):
                     through_key = (
                         old_field.rel.through._meta.app_label,
                         old_field.rel.through._meta.object_name.lower(),
@@ -197,7 +198,9 @@
                         if dep[0] == app_label:
                             # Alright, there's a dependency on the same app.
                             for j, op2 in enumerate(ops):
-                                if self.check_dependency(op2, dep) and j > i:
+                                if j > i and self.check_dependency(op2, dep):
+                                    # shift the operation from position i after
+                                    # the operation at position j
                                     ops = ops[:i] + ops[i + 1:j + 1] + [op] + ops[j + 1:]
                                     found = True
                                     break
@@ -319,7 +322,8 @@
 
     def check_dependency(self, operation, dependency):
         """
-        Checks if an operation dependency matches an operation.
+        Returns ``True`` if the given operation depends on the given dependency,
+        ``False`` otherwise.
         """
         # Created model
         if dependency[2] is None and dependency[3] is True:
@@ -368,6 +372,13 @@
                 operation.name.lower() == dependency[1].lower() and
                 (operation.order_with_respect_to or "").lower() != dependency[2].lower()
             )
+        # Field is removed and part of an index/unique_together
+        elif dependency[2] is not None and dependency[3] == "foo_together_change":
+            return (
+                isinstance(operation, (operations.AlterUniqueTogether,
+                                       operations.AlterIndexTogether)) and
+                operation.name.lower() == dependency[1].lower()
+            )
         # Unknown dependency. Raise an error.
         else:
             raise ValueError("Can't handle dependency %r" % (dependency, ))
@@ -443,13 +454,14 @@
         We also defer any model options that refer to collections of fields
         that might be deferred (e.g. unique_together, index_together).
         """
-        added_models = set(self.new_model_keys) - set(self.old_model_keys)
-        added_unmanaged_models = set(self.new_unmanaged_keys) - set(self.old_unmanaged_keys)
-        models = chain(
+        old_keys = set(self.old_model_keys).union(self.old_unmanaged_keys)
+        added_models = set(self.new_model_keys) - old_keys
+        added_unmanaged_models = set(self.new_unmanaged_keys) - old_keys
+        all_added_models = chain(
             sorted(added_models, key=self.swappable_first_key, reverse=True),
             sorted(added_unmanaged_models, key=self.swappable_first_key, reverse=True)
         )
-        for app_label, model_name in models:
+        for app_label, model_name in all_added_models:
             model_state = self.to_state.models[app_label, model_name]
             model_opts = self.new_apps.get_model(app_label, model_name)._meta
             # Gather related fields
@@ -460,7 +472,7 @@
                     if field.rel.to:
                         if field.primary_key:
                             primary_key_rel = field.rel.to
-                        else:
+                        elif not field.rel.parent_link:
                             related_fields[field.name] = field
                     # through will be none on M2Ms on swapped-out models;
                     # we can treat lack of through as auto_created=True, though.
@@ -619,19 +631,14 @@
         We also bring forward removal of any model options that refer to
         collections of fields - the inverse of generate_created_models().
         """
-        deleted_models = set(self.old_model_keys) - set(self.new_model_keys)
-        deleted_unmanaged_models = set(self.old_unmanaged_keys) - set(self.new_unmanaged_keys)
-        models = chain(sorted(deleted_models), sorted(deleted_unmanaged_models))
-        for app_label, model_name in models:
+        new_keys = set(self.new_model_keys).union(self.new_unmanaged_keys)
+        deleted_models = set(self.old_model_keys) - new_keys
+        deleted_unmanaged_models = set(self.old_unmanaged_keys) - new_keys
+        all_deleted_models = chain(sorted(deleted_models), sorted(deleted_unmanaged_models))
+        for app_label, model_name in all_deleted_models:
             model_state = self.from_state.models[app_label, model_name]
             model = self.old_apps.get_model(app_label, model_name)
             if not model._meta.managed:
-                self.add_operation(
-                    app_label,
-                    operations.DeleteModel(
-                        name=model_state.name,
-                    ),
-                )
                 # Skip here, no need to handle fields for unmanaged models
                 continue
 
@@ -791,8 +798,11 @@
                         None,
                         True
                     ))
-            # You can't just add NOT NULL fields with no default
-            if not field.null and not field.has_default() and not isinstance(field, models.ManyToManyField):
+            # You can't just add NOT NULL fields with no default or fields
+            # which don't allow empty strings as default.
+            if (not field.null and not field.has_default() and
+                    not isinstance(field, models.ManyToManyField) and
+                    not (field.blank and field.empty_strings_allowed)):
                 field = field.clone()
                 field.default = self.questioner.ask_not_null_addition(field_name, model_name)
                 self.add_operation(
@@ -827,9 +837,13 @@
                     model_name=model_name,
                     name=field_name,
                 ),
-                # We might need to depend on the removal of an order_with_respect_to;
+                # We might need to depend on the removal of an
+                # order_with_respect_to or index/unique_together operation;
                 # this is safely ignored if there isn't one
-                dependencies=[(app_label, model_name, field_name, "order_wrt_unset")],
+                dependencies=[
+                    (app_label, model_name, field_name, "order_wrt_unset"),
+                    (app_label, model_name, field_name, "foo_together_change"),
+                ],
             )
 
     def generate_altered_fields(self):
@@ -934,7 +948,18 @@
         makes an operation to represent them in state changes (in case Python
         code in migrations needs them)
         """
-        models_to_check = self.kept_model_keys.union(self.kept_proxy_keys).union(self.kept_unmanaged_keys)
+        models_to_check = self.kept_model_keys.union(
+            self.kept_proxy_keys
+        ).union(
+            self.kept_unmanaged_keys
+        ).union(
+            # unmanaged converted to managed
+            set(self.old_unmanaged_keys).intersection(self.new_model_keys)
+        ).union(
+            # managed converted to unmanaged
+            set(self.old_model_keys).intersection(self.new_unmanaged_keys)
+        )
+
         for app_label, model_name in sorted(models_to_check):
             old_model_name = self.renamed_models.get((app_label, model_name), model_name)
             old_model_state = self.from_state.models[app_label, old_model_name]
@@ -961,7 +986,8 @@
             old_model_name = self.renamed_models.get((app_label, model_name), model_name)
             old_model_state = self.from_state.models[app_label, old_model_name]
             new_model_state = self.to_state.models[app_label, model_name]
-            if old_model_state.options.get("order_with_respect_to", None) != new_model_state.options.get("order_with_respect_to", None):
+            if (old_model_state.options.get("order_with_respect_to", None) !=
+                    new_model_state.options.get("order_with_respect_to", None)):
                 # Make sure it comes second if we're adding
                 # (removal dependency is part of RemoveField)
                 dependencies = []
diff -Nru python-django-1.7.1/django/db/migrations/executor.py python-django-1.7.3/django/db/migrations/executor.py
--- python-django-1.7.1/django/db/migrations/executor.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/executor.py	2015-01-13 19:28:01.000000000 +0100
@@ -36,12 +36,17 @@
             # If the migration is already applied, do backwards mode,
             # otherwise do forwards mode.
             elif target in applied:
-                backwards_plan = self.loader.graph.backwards_plan(target)[:-1]
-                # We only do this if the migration is not the most recent one
-                # in its app - that is, another migration with the same app
-                # label is in the backwards plan
-                if any(node[0] == target[0] for node in backwards_plan):
-                    for migration in backwards_plan:
+                # Don't migrate backwards all the way to the target node (that
+                # may roll back dependencies in other apps that don't need to
+                # be rolled back); instead roll back through target's immediate
+                # child(ren) in the same app, and no further.
+                next_in_app = sorted(
+                    n for n in
+                    self.loader.graph.dependents.get(target, set())
+                    if n[0] == target[0]
+                )
+                for node in next_in_app:
+                    for migration in self.loader.graph.backwards_plan(node):
                         if migration in applied:
                             plan.append((self.loader.graph.nodes[migration], True))
                             applied.remove(migration)
diff -Nru python-django-1.7.1/django/db/migrations/graph.py python-django-1.7.3/django/db/migrations/graph.py
--- python-django-1.7.1/django/db/migrations/graph.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/graph.py	2015-01-13 19:28:01.000000000 +0100
@@ -1,4 +1,5 @@
 from __future__ import unicode_literals
+from collections import deque
 
 from django.utils.datastructures import OrderedSet
 from django.db.migrations.state import ProjectState
@@ -37,9 +38,13 @@
 
     def add_dependency(self, migration, child, parent):
         if child not in self.nodes:
-            raise KeyError("Migration %s dependencies reference nonexistent child node %r" % (migration, child))
+            raise KeyError(
+                "Migration %s dependencies reference nonexistent child node %r" % (migration, child)
+            )
         if parent not in self.nodes:
-            raise KeyError("Migration %s dependencies reference nonexistent parent node %r" % (migration, parent))
+            raise KeyError(
+                "Migration %s dependencies reference nonexistent parent node %r" % (migration, parent)
+            )
         self.dependencies.setdefault(child, set()).add(parent)
         self.dependents.setdefault(parent, set()).add(child)
 
@@ -72,7 +77,8 @@
         """
         roots = set()
         for node in self.nodes:
-            if not any(key[0] == node[0] for key in self.dependencies.get(node, set())) and (not app or app == node[0]):
+            if (not any(key[0] == node[0] for key in self.dependencies.get(node, set()))
+                    and (not app or app == node[0])):
                 roots.add(node)
         return sorted(roots)
 
@@ -86,37 +92,54 @@
         """
         leaves = set()
         for node in self.nodes:
-            if not any(key[0] == node[0] for key in self.dependents.get(node, set())) and (not app or app == node[0]):
+            if (not any(key[0] == node[0] for key in self.dependents.get(node, set()))
+                    and (not app or app == node[0])):
                 leaves.add(node)
         return sorted(leaves)
 
+    def ensure_not_cyclic(self, start, get_children):
+        # Algo from GvR:
+        # http://neopythonic.blogspot.co.uk/2009/01/detecting-cycles-in-directed-graph.html
+        todo = set(self.nodes.keys())
+        while todo:
+            node = todo.pop()
+            stack = [node]
+            while stack:
+                top = stack[-1]
+                for node in get_children(top):
+                    if node in stack:
+                        cycle = stack[stack.index(node):]
+                        raise CircularDependencyError(", ".join("%s.%s" % n for n in cycle))
+                    if node in todo:
+                        stack.append(node)
+                        todo.remove(node)
+                        break
+                else:
+                    node = stack.pop()
+
     def dfs(self, start, get_children):
         """
         Dynamic programming based depth first search, for finding dependencies.
         """
-        visited = []
+        self.ensure_not_cyclic(start, get_children)
+        visited = deque()
         visited.append(start)
-        path = [start]
-        stack = sorted(get_children(start))
+        stack = deque(sorted(get_children(start)))
         while stack:
-            node = stack.pop(0)
-
-            if node in path:
-                raise CircularDependencyError()
-            path.append(node)
-
-            visited.insert(0, node)
-            children = sorted(get_children(node))
-
-            if not children:
-                path = []
-
-            stack = children + stack
+            node = stack.popleft()
+            visited.appendleft(node)
+            children = sorted(get_children(node), reverse=True)
+            # reverse sorting is needed because prepending using deque.extendleft
+            # also effectively reverses values
+            stack.extendleft(children)
 
         return list(OrderedSet(visited))
 
     def __str__(self):
-        return "Graph: %s nodes, %s edges" % (len(self.nodes), sum(len(x) for x in self.dependencies.values()))
+        return "Graph: %s nodes, %s edges" % (
+            len(self.nodes),
+            sum(len(x) for x in self.dependencies.values()),
+        )
 
     def make_state(self, nodes=None, at_end=True, real_apps=None):
         """
diff -Nru python-django-1.7.1/django/db/migrations/loader.py python-django-1.7.3/django/db/migrations/loader.py
--- python-django-1.7.1/django/db/migrations/loader.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/loader.py	2015-01-13 19:28:01.000000000 +0100
@@ -108,7 +108,9 @@
                         break
                     raise
                 if not hasattr(migration_module, "Migration"):
-                    raise BadMigrationError("Migration %s in app %s has no Migration class" % (migration_name, app_config.label))
+                    raise BadMigrationError(
+                        "Migration %s in app %s has no Migration class" % (migration_name, app_config.label)
+                    )
                 # Ignore South-style migrations
                 if hasattr(migration_module.Migration, "forwards"):
                     south_style_migrations = True
@@ -129,7 +131,9 @@
             if l == app_label and n.startswith(name_prefix):
                 results.append((l, n))
         if len(results) > 1:
-            raise AmbiguityError("There is more than one migration for '%s' with the prefix '%s'" % (app_label, name_prefix))
+            raise AmbiguityError(
+                "There is more than one migration for '%s' with the prefix '%s'" % (app_label, name_prefix)
+            )
         elif len(results) == 0:
             raise KeyError("There no migrations for '%s' with the prefix '%s'" % (app_label, name_prefix))
         else:
diff -Nru python-django-1.7.1/django/db/migrations/migration.py python-django-1.7.3/django/db/migrations/migration.py
--- python-django-1.7.1/django/db/migrations/migration.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/migration.py	2015-01-13 19:28:05.000000000 +0100
@@ -90,7 +90,8 @@
             # there instead
             if collect_sql and not operation.reduces_to_sql:
                 schema_editor.collected_sql.append("--")
-                schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS SQL:")
+                schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE "
+                                                   "WRITTEN AS SQL:")
                 schema_editor.collected_sql.append("-- %s" % operation.describe())
                 schema_editor.collected_sql.append("--")
                 continue
@@ -114,28 +115,39 @@
         Takes a project_state representing all migrations prior to this one
         and a schema_editor for a live database and applies the migration
         in a reverse order.
+
+        The backwards migration process consists of two phases:
+
+        1. The intermediate states from right before the first until right
+           after the last operation inside this migration are preserved.
+        2. The operations are applied in reverse order using the states
+           recorded in step 1.
         """
-        # We need to pre-calculate the stack of project states
+        # Construct all the intermediate states we need for a reverse migration
         to_run = []
+        new_state = project_state
+        # Phase 1
         for operation in self.operations:
-            # If this operation cannot be represented as SQL, place a comment
-            # there instead
-            if collect_sql and not operation.reduces_to_sql:
-                schema_editor.collected_sql.append("--")
-                schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS SQL:")
-                schema_editor.collected_sql.append("-- %s" % operation.describe())
-                schema_editor.collected_sql.append("--")
-                continue
             # If it's irreversible, error out
             if not operation.reversible:
                 raise Migration.IrreversibleError("Operation %s in %s is not reversible" % (operation, self))
-            new_state = project_state.clone()
+            # Preserve new state from previous run to not tamper the same state
+            # over all operations
+            new_state = new_state.clone()
+            old_state = new_state.clone()
             operation.state_forwards(self.app_label, new_state)
-            to_run.append((operation, project_state, new_state))
-            project_state = new_state
-        # Now run them in reverse
-        to_run.reverse()
+            to_run.insert(0, (operation, old_state, new_state))
+
+        # Phase 2
         for operation, to_state, from_state in to_run:
+            if collect_sql:
+                if not operation.reduces_to_sql:
+                    schema_editor.collected_sql.append("--")
+                    schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE "
+                                                       "WRITTEN AS SQL:")
+                    schema_editor.collected_sql.append("-- %s" % operation.describe())
+                    schema_editor.collected_sql.append("--")
+                    continue
             if not schema_editor.connection.features.can_rollback_ddl and operation.atomic:
                 # We're forcing a transaction on a non-transactional-DDL backend
                 with atomic(schema_editor.connection.alias):
diff -Nru python-django-1.7.1/django/db/migrations/operations/base.py python-django-1.7.3/django/db/migrations/operations/base.py
--- python-django-1.7.1/django/db/migrations/operations/base.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/operations/base.py	2015-01-13 19:28:01.000000000 +0100
@@ -104,10 +104,10 @@
         if it's a proxy, if it's managed, and if it's swapped out.
         """
         return (
-            router.allow_migrate(connection_alias, model) and
             not model._meta.proxy and
             not model._meta.swapped and
-            model._meta.managed
+            model._meta.managed and
+            router.allow_migrate(connection_alias, model)
         )
 
     def __repr__(self):
diff -Nru python-django-1.7.1/django/db/migrations/operations/fields.py python-django-1.7.3/django/db/migrations/operations/fields.py
--- python-django-1.7.1/django/db/migrations/operations/fields.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/operations/fields.py	2015-01-13 19:28:01.000000000 +0100
@@ -26,9 +26,9 @@
         state.models[app_label, self.model_name.lower()].fields.append((self.name, field))
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        from_model = from_state.render().get_model(app_label, self.model_name)
         to_model = to_state.render().get_model(app_label, self.model_name)
         if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
+            from_model = from_state.render().get_model(app_label, self.model_name)
             field = to_model._meta.get_field_by_name(self.name)[0]
             if not self.preserve_default:
                 field.default = self.field.default
@@ -84,9 +84,9 @@
             schema_editor.remove_field(from_model, from_model._meta.get_field_by_name(self.name)[0])
 
     def database_backwards(self, app_label, schema_editor, from_state, to_state):
-        from_model = from_state.render().get_model(app_label, self.model_name)
         to_model = to_state.render().get_model(app_label, self.model_name)
         if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
+            from_model = from_state.render().get_model(app_label, self.model_name)
             schema_editor.add_field(from_model, to_model._meta.get_field_by_name(self.name)[0])
 
     def describe(self):
@@ -121,9 +121,9 @@
         ]
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        from_model = from_state.render().get_model(app_label, self.model_name)
         to_model = to_state.render().get_model(app_label, self.model_name)
         if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
+            from_model = from_state.render().get_model(app_label, self.model_name)
             from_field = from_model._meta.get_field_by_name(self.name)[0]
             to_field = to_model._meta.get_field_by_name(self.name)[0]
             # If the field is a relatedfield with an unresolved rel.to, just
@@ -174,20 +174,22 @@
     def state_forwards(self, app_label, state):
         # Rename the field
         state.models[app_label, self.model_name.lower()].fields = [
-            (self.new_name if n == self.old_name else n, f) for n, f in state.models[app_label, self.model_name.lower()].fields
+            (self.new_name if n == self.old_name else n, f)
+            for n, f in state.models[app_label, self.model_name.lower()].fields
         ]
-        # Fix unique_together to refer to the new field
+        # Fix index/unique_together to refer to the new field
         options = state.models[app_label, self.model_name.lower()].options
-        if "unique_together" in options:
-            options['unique_together'] = [
-                [self.new_name if n == self.old_name else n for n in unique]
-                for unique in options['unique_together']
-            ]
+        for option in ('index_together', 'unique_together'):
+            if option in options:
+                options[option] = [
+                    [self.new_name if n == self.old_name else n for n in together]
+                    for together in options[option]
+                ]
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        from_model = from_state.render().get_model(app_label, self.model_name)
         to_model = to_state.render().get_model(app_label, self.model_name)
         if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
+            from_model = from_state.render().get_model(app_label, self.model_name)
             schema_editor.alter_field(
                 from_model,
                 from_model._meta.get_field_by_name(self.old_name)[0],
@@ -195,9 +197,9 @@
             )
 
     def database_backwards(self, app_label, schema_editor, from_state, to_state):
-        from_model = from_state.render().get_model(app_label, self.model_name)
         to_model = to_state.render().get_model(app_label, self.model_name)
         if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
+            from_model = from_state.render().get_model(app_label, self.model_name)
             schema_editor.alter_field(
                 from_model,
                 from_model._meta.get_field_by_name(self.new_name)[0],
diff -Nru python-django-1.7.1/django/db/migrations/operations/models.py python-django-1.7.3/django/db/migrations/operations/models.py
--- python-django-1.7.1/django/db/migrations/operations/models.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/operations/models.py	2015-01-13 19:28:01.000000000 +0100
@@ -106,8 +106,6 @@
     Renames a model.
     """
 
-    reversible = False
-
     def __init__(self, old_name, new_name):
         self.old_name = old_name
         self.new_name = new_name
@@ -141,11 +139,11 @@
             state.models[related_key].fields = new_fields
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        old_apps = from_state.render()
         new_apps = to_state.render()
-        old_model = old_apps.get_model(app_label, self.old_name)
         new_model = new_apps.get_model(app_label, self.new_name)
         if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
+            old_apps = from_state.render()
+            old_model = old_apps.get_model(app_label, self.old_name)
             # Move the main table
             schema_editor.alter_db_table(
                 new_model,
@@ -202,16 +200,24 @@
         state.models[app_label, self.name.lower()].options["db_table"] = self.table
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        old_apps = from_state.render()
         new_apps = to_state.render()
-        old_model = old_apps.get_model(app_label, self.name)
         new_model = new_apps.get_model(app_label, self.name)
         if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
+            old_apps = from_state.render()
+            old_model = old_apps.get_model(app_label, self.name)
             schema_editor.alter_db_table(
                 new_model,
                 old_model._meta.db_table,
                 new_model._meta.db_table,
             )
+            # Rename M2M fields whose name is based on this model's db_table
+            for (old_field, new_field) in zip(old_model._meta.local_many_to_many, new_model._meta.local_many_to_many):
+                if new_field.rel.through._meta.auto_created:
+                    schema_editor.alter_db_table(
+                        new_field.rel.through,
+                        old_field.rel.through._meta.db_table,
+                        new_field.rel.through._meta.db_table,
+                    )
 
     def database_backwards(self, app_label, schema_editor, from_state, to_state):
         return self.database_forwards(app_label, schema_editor, from_state, to_state)
@@ -240,11 +246,11 @@
         model_state.options[self.option_name] = self.unique_together
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        old_apps = from_state.render()
         new_apps = to_state.render()
-        old_model = old_apps.get_model(app_label, self.name)
         new_model = new_apps.get_model(app_label, self.name)
         if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
+            old_apps = from_state.render()
+            old_model = old_apps.get_model(app_label, self.name)
             schema_editor.alter_unique_together(
                 new_model,
                 getattr(old_model._meta, self.option_name, set()),
@@ -278,11 +284,11 @@
         model_state.options[self.option_name] = self.index_together
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        old_apps = from_state.render()
         new_apps = to_state.render()
-        old_model = old_apps.get_model(app_label, self.name)
         new_model = new_apps.get_model(app_label, self.name)
         if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
+            old_apps = from_state.render()
+            old_model = old_apps.get_model(app_label, self.name)
             schema_editor.alter_index_together(
                 new_model,
                 getattr(old_model._meta, self.option_name, set()),
@@ -313,9 +319,9 @@
         model_state.options['order_with_respect_to'] = self.order_with_respect_to
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        from_model = from_state.render().get_model(app_label, self.name)
         to_model = to_state.render().get_model(app_label, self.name)
         if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
+            from_model = from_state.render().get_model(app_label, self.name)
             # Remove a field if we need to
             if from_model._meta.order_with_respect_to and not to_model._meta.order_with_respect_to:
                 schema_editor.remove_field(from_model, from_model._meta.get_field_by_name("_order")[0])
@@ -323,6 +329,8 @@
             # it's likely a rename)
             elif to_model._meta.order_with_respect_to and not from_model._meta.order_with_respect_to:
                 field = to_model._meta.get_field_by_name("_order")[0]
+                if not field.has_default():
+                    field.default = 0
                 schema_editor.add_field(
                     from_model,
                     field,
@@ -348,6 +356,7 @@
     # Model options we want to compare and preserve in an AlterModelOptions op
     ALTER_OPTION_KEYS = [
         "get_latest_by",
+        "managed",
         "ordering",
         "permissions",
         "default_permissions",
diff -Nru python-django-1.7.1/django/db/migrations/optimizer.py python-django-1.7.3/django/db/migrations/optimizer.py
--- python-django-1.7.1/django/db/migrations/optimizer.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/optimizer.py	2015-01-13 19:28:01.000000000 +0100
@@ -300,7 +300,8 @@
             return [other]
 
     def reduce_add_field_rename_field(self, operation, other, in_between):
-        if operation.model_name.lower() == other.model_name.lower() and operation.name.lower() == other.old_name.lower():
+        if (operation.model_name.lower() == other.model_name.lower() and
+                operation.name.lower() == other.old_name.lower()):
             return [
                 migrations.AddField(
                     model_name=operation.model_name,
@@ -310,7 +311,8 @@
             ]
 
     def reduce_alter_field_rename_field(self, operation, other, in_between):
-        if operation.model_name.lower() == other.model_name.lower() and operation.name.lower() == other.old_name.lower():
+        if (operation.model_name.lower() == other.model_name.lower() and
+                operation.name.lower() == other.old_name.lower()):
             return [
                 other,
                 migrations.AlterField(
@@ -321,7 +323,8 @@
             ]
 
     def reduce_rename_field_self(self, operation, other, in_between):
-        if operation.model_name.lower() == other.model_name.lower() and operation.new_name.lower() == other.old_name.lower():
+        if (operation.model_name.lower() == other.model_name.lower() and
+                operation.new_name.lower() == other.old_name.lower()):
             return [
                 migrations.RenameField(
                     operation.model_name,
diff -Nru python-django-1.7.1/django/db/migrations/questioner.py python-django-1.7.3/django/db/migrations/questioner.py
--- python-django-1.7.1/django/db/migrations/questioner.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/questioner.py	2015-01-06 02:20:47.000000000 +0100
@@ -163,11 +163,15 @@
 
     def ask_rename(self, model_name, old_name, new_name, field_instance):
         "Was this field really renamed?"
-        return self._boolean_input("Did you rename %s.%s to %s.%s (a %s)? [y/N]" % (model_name, old_name, model_name, new_name, field_instance.__class__.__name__), False)
+        msg = "Did you rename %s.%s to %s.%s (a %s)? [y/N]"
+        return self._boolean_input(msg % (model_name, old_name, model_name, new_name,
+                                          field_instance.__class__.__name__), False)
 
     def ask_rename_model(self, old_model_state, new_model_state):
         "Was this model really renamed?"
-        return self._boolean_input("Did you rename the %s.%s model to %s? [y/N]" % (old_model_state.app_label, old_model_state.name, new_model_state.name), False)
+        msg = "Did you rename the %s.%s model to %s? [y/N]"
+        return self._boolean_input(msg % (old_model_state.app_label, old_model_state.name,
+                                          new_model_state.name), False)
 
     def ask_merge(self, app_label):
         return self._boolean_input(
diff -Nru python-django-1.7.1/django/db/migrations/state.py python-django-1.7.3/django/db/migrations/state.py
--- python-django-1.7.1/django/db/migrations/state.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/state.py	2015-01-13 19:28:01.000000000 +0100
@@ -68,7 +68,12 @@
                     except InvalidBasesError:
                         new_unrendered_models.append(model)
                 if len(new_unrendered_models) == len(unrendered_models):
-                    raise InvalidBasesError("Cannot resolve bases for %r\nThis can happen if you are inheriting models from an app with migrations (e.g. contrib.auth)\n in an app with no migrations; see https://docs.djangoproject.com/en/1.7/topics/migrations/#dependencies for more" % new_unrendered_models)
+                    raise InvalidBasesError(
+                        "Cannot resolve bases for %r\nThis can happen if you are inheriting models from an "
+                        "app with migrations (e.g. contrib.auth)\n in an app with no migrations; see "
+                        "https://docs.djangoproject.com/en/1.7/topics/migrations/#dependencies "
+                        "for more" % new_unrendered_models
+                    )
                 unrendered_models = new_unrendered_models
             # make sure apps has no dangling references
             if self.apps._pending_lookups:
@@ -78,16 +83,15 @@
                     try:
                         model = self.apps.get_model(lookup_model[0], lookup_model[1])
                     except LookupError:
-                        if "%s.%s" % (lookup_model[0], lookup_model[1]) == settings.AUTH_USER_MODEL and ignore_swappable:
+                        app_label = "%s.%s" % (lookup_model[0], lookup_model[1])
+                        if app_label == settings.AUTH_USER_MODEL and ignore_swappable:
                             continue
                         # Raise an error with a best-effort helpful message
                         # (only for the first issue). Error message should look like:
                         # "ValueError: Lookup failed for model referenced by
                         # field migrations.Book.author: migrations.Author"
-                        raise ValueError("Lookup failed for model referenced by field {field}: {model[0]}.{model[1]}".format(
-                            field=operations[0][1],
-                            model=lookup_model,
-                        ))
+                        msg = "Lookup failed for model referenced by field {field}: {model[0]}.{model[1]}"
+                        raise ValueError(msg.format(field=operations[0][1], model=lookup_model))
                     else:
                         do_pending_lookups(model)
         try:
@@ -326,7 +330,8 @@
             (self.app_label == other.app_label) and
             (self.name == other.name) and
             (len(self.fields) == len(other.fields)) and
-            all((k1 == k2 and (f1.deconstruct()[1:] == f2.deconstruct()[1:])) for (k1, f1), (k2, f2) in zip(self.fields, other.fields)) and
+            all((k1 == k2 and (f1.deconstruct()[1:] == f2.deconstruct()[1:]))
+                for (k1, f1), (k2, f2) in zip(self.fields, other.fields)) and
             (self.options == other.options) and
             (self.bases == other.bases)
         )
diff -Nru python-django-1.7.1/django/db/migrations/writer.py python-django-1.7.3/django/db/migrations/writer.py
--- python-django-1.7.1/django/db/migrations/writer.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/migrations/writer.py	2015-01-13 19:28:01.000000000 +0100
@@ -1,10 +1,11 @@
 from __future__ import unicode_literals
 
+import collections
 import datetime
-import inspect
 import decimal
-import collections
 from importlib import import_module
+import inspect
+import math
 import os
 import re
 import sys
@@ -155,10 +156,12 @@
         imports.discard("from django.db import models")
         items["imports"] = "\n".join(imports) + "\n" if imports else ""
         if migration_imports:
-            items["imports"] += "\n\n# Functions from the following migrations need manual copying.\n# Move them and any dependencies into this file, then update the\n# RunPython operations to refer to the local versions:\n# %s" % (
-                "\n# ".join(migration_imports)
-            )
-
+            items["imports"] += (
+                "\n\n# Functions from the following migrations need manual "
+                "copying.\n# Move them and any dependencies into this file, "
+                "then update the\n# RunPython operations to refer to the local "
+                "versions:\n# %s"
+            ) % "\n# ".join(migration_imports)
         # If there's a replaces, make a string for it
         if self.migration.replaces:
             items['replaces_str'] = "\n    replaces = %s\n" % self.serialize(self.migration.replaces)[0]
@@ -296,12 +299,18 @@
         # Times
         elif isinstance(value, datetime.time):
             value_repr = repr(value)
-            return value_repr, set(["import datetime"])
+            if isinstance(value, datetime_safe.time):
+                value_repr = "datetime.%s" % value_repr
+            return value_repr, {"import datetime"}
         # Settings references
         elif isinstance(value, SettingsReference):
             return "settings.%s" % value.setting_name, set(["from django.conf import settings"])
         # Simple types
-        elif isinstance(value, six.integer_types + (float, bool, type(None))):
+        elif isinstance(value, float):
+            if math.isnan(value) or math.isinf(value):
+                return 'float("{}")'.format(value), set()
+            return repr(value), set()
+        elif isinstance(value, six.integer_types + (bool, type(None))):
             return repr(value), set()
         elif isinstance(value, six.binary_type):
             value_repr = repr(value)
@@ -322,6 +331,20 @@
         elif isinstance(value, models.Field):
             attr_name, path, args, kwargs = value.deconstruct()
             return cls.serialize_deconstructed(path, args, kwargs)
+        # Classes
+        elif isinstance(value, type):
+            special_cases = [
+                (models.Model, "models.Model", []),
+            ]
+            for case, string, imports in special_cases:
+                if case is value:
+                    return string, set(imports)
+            if hasattr(value, "__module__"):
+                module = value.__module__
+                if module == six.moves.builtins.__name__:
+                    return value.__name__, set()
+                else:
+                    return "%s.%s" % (module, value.__name__), {"import %s" % module}
         # Anything that knows how to deconstruct itself.
         elif hasattr(value, 'deconstruct'):
             return cls.serialize_deconstructed(*value.deconstruct())
@@ -355,20 +378,6 @@
                     "For more information, see https://docs.djangoproject.com/en/1.7/topics/migrations/#serializing-values"
                     % (value.__name__, module_name))
             return "%s.%s" % (module_name, value.__name__), set(["import %s" % module_name])
-        # Classes
-        elif isinstance(value, type):
-            special_cases = [
-                (models.Model, "models.Model", []),
-            ]
-            for case, string, imports in special_cases:
-                if case is value:
-                    return string, set(imports)
-            if hasattr(value, "__module__"):
-                module = value.__module__
-                if module == six.moves.builtins.__name__:
-                    return value.__name__, set()
-                else:
-                    return "%s.%s" % (module, value.__name__), set(["import %s" % module])
         # Other iterables
         elif isinstance(value, collections.Iterable):
             imports = set()
@@ -394,7 +403,11 @@
             return "re.compile(%s)" % ', '.join(args), imports
         # Uh oh.
         else:
-            raise ValueError("Cannot serialize: %r\nThere are some values Django cannot serialize into migration files.\nFor more, see https://docs.djangoproject.com/en/dev/topics/migrations/#migration-serializing" % value)
+            raise ValueError(
+                "Cannot serialize: %r\nThere are some values Django cannot serialize into "
+                "migration files.\nFor more, see https://docs.djangoproject.com/en/dev/"
+                "topics/migrations/#migration-serializing" % value
+            )
 
 
 MIGRATION_TEMPLATE = """\
diff -Nru python-django-1.7.1/django/db/models/base.py python-django-1.7.3/django/db/models/base.py
--- python-django-1.7.1/django/db/models/base.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/models/base.py	2015-01-13 19:28:01.000000000 +0100
@@ -98,13 +98,11 @@
                 msg = (
                     "Model class %s.%s doesn't declare an explicit app_label "
                     "and either isn't in an application in INSTALLED_APPS or "
-                    "else was imported before its application was loaded. " %
+                    "else was imported before its application was loaded. "
+                    "This will no longer be supported in Django 1.9." %
                     (module, name))
-                if abstract:
-                    msg += "Its app_label will be set to None in Django 1.9."
-                else:
-                    msg += "This will no longer be supported in Django 1.9."
-                warnings.warn(msg, RemovedInDjango19Warning, stacklevel=2)
+                if not abstract:
+                    warnings.warn(msg, RemovedInDjango19Warning, stacklevel=2)
 
                 model_module = sys.modules[new_class.__module__]
                 package_components = model_module.__name__.split('.')
@@ -1461,6 +1459,8 @@
     Used to unpickle Model subclasses with deferred fields.
     """
     if isinstance(model_id, tuple):
+        if not apps.ready:
+            apps.populate(settings.INSTALLED_APPS)
         model = apps.get_model(*model_id)
     else:
         # Backwards compat - the model was cached directly in earlier versions.
diff -Nru python-django-1.7.1/django/db/models/fields/__init__.py python-django-1.7.3/django/db/models/fields/__init__.py
--- python-django-1.7.1/django/db/models/fields/__init__.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/models/fields/__init__.py	2015-01-13 19:28:01.000000000 +0100
@@ -1272,9 +1272,13 @@
             # For backwards compatibility, interpret naive datetimes in local
             # time. This won't work during DST change, but we can't do much
             # about it, so we let the exceptions percolate up the call stack.
-            warnings.warn("DateTimeField %s.%s received a naive datetime (%s)"
+            try:
+                name = '%s.%s' % (self.model.__name__, self.name)
+            except AttributeError:
+                name = '(unbound)'
+            warnings.warn("DateTimeField %s received a naive datetime (%s)"
                           " while time zone support is active." %
-                          (self.model.__name__, self.name, value),
+                          (name, value),
                           RuntimeWarning)
             default_timezone = timezone.get_default_timezone()
             value = timezone.make_aware(value, default_timezone)
diff -Nru python-django-1.7.1/django/db/models/fields/related.py python-django-1.7.3/django/db/models/fields/related.py
--- python-django-1.7.1/django/db/models/fields/related.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/models/fields/related.py	2015-01-13 19:28:01.000000000 +0100
@@ -259,7 +259,7 @@
             sup.contribute_to_class(cls, name, virtual_only=virtual_only)
 
         if not cls._meta.abstract and self.rel.related_name:
-            related_name = self.rel.related_name % {
+            related_name = force_text(self.rel.related_name) % {
                 'class': cls.__name__.lower(),
                 'app_label': cls._meta.app_label.lower()
             }
@@ -1376,7 +1376,7 @@
         kwargs['from_fields'] = self.from_fields
         kwargs['to_fields'] = self.to_fields
         if self.rel.related_name is not None:
-            kwargs['related_name'] = force_text(self.rel.related_name)
+            kwargs['related_name'] = self.rel.related_name
         if self.rel.related_query_name is not None:
             kwargs['related_query_name'] = self.rel.related_query_name
         if self.rel.on_delete != CASCADE:
@@ -2112,7 +2112,7 @@
         if self.rel.db_constraint is not True:
             kwargs['db_constraint'] = self.rel.db_constraint
         if self.rel.related_name is not None:
-            kwargs['related_name'] = force_text(self.rel.related_name)
+            kwargs['related_name'] = self.rel.related_name
         if self.rel.related_query_name is not None:
             kwargs['related_query_name'] = self.rel.related_query_name
         # Rel needs more work.
diff -Nru python-django-1.7.1/django/db/models/sql/compiler.py python-django-1.7.3/django/db/models/sql/compiler.py
--- python-django-1.7.1/django/db/models/sql/compiler.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/models/sql/compiler.py	2015-01-13 19:28:01.000000000 +0100
@@ -56,7 +56,7 @@
         if name in self.quote_cache:
             return self.quote_cache[name]
         if ((name in self.query.alias_map and name not in self.query.table_map) or
-                name in self.query.extra_select):
+                name in self.query.extra_select or name in self.query.external_aliases):
             self.quote_cache[name] = name
             return name
         r = self.connection.ops.quote_name(name)
diff -Nru python-django-1.7.1/django/db/models/sql/query.py python-django-1.7.3/django/db/models/sql/query.py
--- python-django-1.7.1/django/db/models/sql/query.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/models/sql/query.py	2015-01-13 19:28:01.000000000 +0100
@@ -6,6 +6,8 @@
 databases). The abstraction barrier only works one way: this module has to know
 all about the internals of models in order to get the information it needs.
 """
+from string import ascii_uppercase
+from itertools import count, product
 
 from collections import OrderedDict
 import copy
@@ -114,6 +116,10 @@
         # type they are. The key is the alias of the joined table (possibly
         # the table name) and the value is JoinInfo from constants.py.
         self.alias_map = {}
+        # Sometimes the query contains references to aliases in outer queries (as
+        # a result of split_exclude). Correct alias quoting needs to know these
+        # aliases too.
+        self.external_aliases = set()
         self.table_map = {}     # Maps table names to list of aliases.
         self.join_map = {}
         self.default_cols = True
@@ -241,6 +247,7 @@
         obj.model = self.model
         obj.alias_refcount = self.alias_refcount.copy()
         obj.alias_map = self.alias_map.copy()
+        obj.external_aliases = self.external_aliases.copy()
         obj.table_map = self.table_map.copy()
         obj.join_map = self.join_map.copy()
         obj.default_cols = self.default_cols
@@ -335,6 +342,11 @@
             # Return value depends on the type of the field being processed.
             return self.convert_values(value, aggregate.field, connection)
 
+    def relabeled_clone(self, change_map):
+        clone = self.clone()
+        clone.change_aliases(change_map)
+        return clone
+
     def get_aggregation(self, using, force_subq=False):
         """
         Returns the dictionary with the values of the existing aggregations.
@@ -788,7 +800,9 @@
             ident = (change_map.get(ident[0], ident[0]),) + ident[1:]
             self.join_map[ident] = aliases
         for old_alias, new_alias in six.iteritems(change_map):
-            alias_data = self.alias_map[old_alias]
+            alias_data = self.alias_map.get(old_alias)
+            if alias_data is None:
+                continue
             alias_data = alias_data._replace(rhs_alias=new_alias)
             self.alias_refcount[new_alias] = self.alias_refcount[old_alias]
             del self.alias_refcount[old_alias]
@@ -815,6 +829,9 @@
                 data = data._replace(lhs_alias=change_map[lhs])
                 self.alias_map[alias] = data
 
+        self.external_aliases = {change_map.get(alias, alias)
+                                 for alias in self.external_aliases}
+
     def bump_prefix(self, outer_query):
         """
         Changes the alias prefix to the next letter in the alphabet in a way
@@ -822,13 +839,37 @@
         conflict. Even tables that previously had no alias will get an alias
         after this call.
         """
+        def prefix_gen():
+            """
+            Generates a sequence of characters in alphabetical order:
+                -> 'A', 'B', 'C', ...
+
+            When the alphabet is finished, the sequence will continue with the
+            Cartesian product:
+                -> 'AA', 'AB', 'AC', ...
+            """
+            alphabet = ascii_uppercase
+            prefix = chr(ord(self.alias_prefix) + 1)
+            yield prefix
+            for n in count(1):
+                seq = alphabet[alphabet.index(prefix):] if prefix else alphabet
+                for s in product(seq, repeat=n):
+                    yield ''.join(s)
+                prefix = None
+
         if self.alias_prefix != outer_query.alias_prefix:
             # No clashes between self and outer query should be possible.
             return
-        self.alias_prefix = chr(ord(self.alias_prefix) + 1)
-        while self.alias_prefix in self.subq_aliases:
-            self.alias_prefix = chr(ord(self.alias_prefix) + 1)
-            assert self.alias_prefix < 'Z'
+
+        local_recursion_limit = 127  # explicitly avoid infinite loop
+        for pos, prefix in enumerate(prefix_gen()):
+            if prefix not in self.subq_aliases:
+                self.alias_prefix = prefix
+                break
+            if pos > local_recursion_limit:
+                raise RuntimeError(
+                    'Maximum recursion depth exceeded: too many subqueries.'
+                )
         self.subq_aliases = self.subq_aliases.union([self.alias_prefix])
         outer_query.subq_aliases = outer_query.subq_aliases.union(self.subq_aliases)
         change_map = OrderedDict()
@@ -1048,6 +1089,9 @@
         elif isinstance(value, ExpressionNode):
             # If value is a query expression, evaluate it
             value = SQLEvaluator(value, self, reuse=can_reuse)
+        # Subqueries need to use a different set of aliases than the
+        # outer query. Call bump_prefix to change aliases of the inner
+        # query (the value).
         if hasattr(value, 'query') and hasattr(value.query, 'bump_prefix'):
             value = value._clone()
             value.query.bump_prefix(self)
@@ -1509,6 +1553,7 @@
             lookup = lookup_class(Col(query.select[0].col[0], pk, pk),
                                   Col(alias, pk, pk))
             query.where.add(lookup, AND)
+            query.external_aliases.add(alias)
 
         condition, needed_inner = self.build_filter(
             ('%s__in' % trimmed_prefix, query),
diff -Nru python-django-1.7.1/django/db/utils.py python-django-1.7.3/django/db/utils.py
--- python-django-1.7.1/django/db/utils.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/db/utils.py	2015-01-13 19:28:01.000000000 +0100
@@ -216,7 +216,7 @@
             else:
                 test_settings.update(old_test_settings)
                 for key, _ in six.iteritems(old_test_settings):
-                    warnings.warn("In Django 1.9 the %s connection setting will be moved "
+                    warnings.warn("In Django 1.9 the TEST_%s connection setting will be moved "
                                   "to a %s entry in the TEST setting" %
                                   (self.TEST_SETTING_RENAMES_REVERSE.get(key, key), key),
                                   RemovedInDjango19Warning, stacklevel=2)
diff -Nru python-django-1.7.1/django/forms/fields.py python-django-1.7.3/django/forms/fields.py
--- python-django-1.7.1/django/forms/fields.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/forms/fields.py	2015-01-13 19:28:01.000000000 +0100
@@ -171,17 +171,6 @@
         """
         return {}
 
-    def get_limit_choices_to(self):
-        """
-        Returns ``limit_choices_to`` for this form field.
-
-        If it is a callable, it will be invoked and the result will be
-        returned.
-        """
-        if callable(self.limit_choices_to):
-            return self.limit_choices_to()
-        return self.limit_choices_to
-
     def _has_changed(self, initial, data):
         """
         Return True if data differs from initial.
@@ -1079,7 +1068,11 @@
             if not isinstance(initial, list):
                 initial = self.widget.decompress(initial)
         for field, initial, data in zip(self.fields, initial, data):
-            if field._has_changed(field.to_python(initial), data):
+            try:
+                initial = field.to_python(initial)
+            except ValidationError:
+                return True
+            if field._has_changed(initial, data):
                 return True
         return False
 
diff -Nru python-django-1.7.1/django/forms/models.py python-django-1.7.3/django/forms/models.py
--- python-django-1.7.1/django/forms/models.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/forms/models.py	2015-01-13 19:28:05.000000000 +0100
@@ -329,11 +329,9 @@
         # Apply ``limit_choices_to`` to each field.
         for field_name in self.fields:
             formfield = self.fields[field_name]
-            if hasattr(formfield, 'queryset'):
-                limit_choices_to = formfield.limit_choices_to
+            if hasattr(formfield, 'queryset') and hasattr(formfield, 'get_limit_choices_to'):
+                limit_choices_to = formfield.get_limit_choices_to()
                 if limit_choices_to is not None:
-                    if callable(limit_choices_to):
-                        limit_choices_to = limit_choices_to()
                     formfield.queryset = formfield.queryset.complex_filter(limit_choices_to)
 
     def _get_validation_exclusions(self):
@@ -571,7 +569,7 @@
     def _get_to_python(self, field):
         """
         If the field is a related field, fetch the concrete field's (that
-        is, the ultimate pointed-to field's) get_prep_value.
+        is, the ultimate pointed-to field's) to_python.
         """
         while field.rel is not None:
             field = field.rel.get_related_field()
@@ -1118,6 +1116,17 @@
         self.choice_cache = None
         self.to_field_name = to_field_name
 
+    def get_limit_choices_to(self):
+        """
+        Returns ``limit_choices_to`` for this form field.
+
+        If it is a callable, it will be invoked and the result will be
+        returned.
+        """
+        if callable(self.limit_choices_to):
+            return self.limit_choices_to()
+        return self.limit_choices_to
+
     def __deepcopy__(self, memo):
         result = super(ChoiceField, self).__deepcopy__(memo)
         # Need to force a new ModelChoiceIterator to be created, bug #11183
@@ -1212,8 +1221,7 @@
     def to_python(self, value):
         if not value:
             return []
-        to_py = super(ModelMultipleChoiceField, self).to_python
-        return [to_py(val) for val in value]
+        return list(self._check_values(value))
 
     def clean(self, value):
         if self.required and not value:
@@ -1222,7 +1230,29 @@
             return self.queryset.none()
         if not isinstance(value, (list, tuple)):
             raise ValidationError(self.error_messages['list'], code='list')
+        qs = self._check_values(value)
+        # Since this overrides the inherited ModelChoiceField.clean
+        # we run custom validators here
+        self.run_validators(value)
+        return qs
+
+    def _check_values(self, value):
+        """
+        Given a list of possible PK values, returns a QuerySet of the
+        corresponding objects. Raises a ValidationError if a given value is
+        invalid (not a valid PK, not in the queryset, etc.)
+        """
         key = self.to_field_name or 'pk'
+        # deduplicate given values to avoid creating many querysets or
+        # requiring the database backend deduplicate efficiently.
+        try:
+            value = frozenset(value)
+        except TypeError:
+            # list of lists isn't hashable, for example
+            raise ValidationError(
+                self.error_messages['list'],
+                code='list',
+            )
         for pk in value:
             try:
                 self.queryset.filter(**{key: pk})
@@ -1241,9 +1271,6 @@
                     code='invalid_choice',
                     params={'value': val},
                 )
-        # Since this overrides the inherited ModelChoiceField.clean
-        # we run custom validators here
-        self.run_validators(value)
         return qs
 
     def prepare_value(self, value):
diff -Nru python-django-1.7.1/django/__init__.py python-django-1.7.3/django/__init__.py
--- python-django-1.7.1/django/__init__.py	2014-10-22 18:55:10.000000000 +0200
+++ python-django-1.7.3/django/__init__.py	2015-01-13 19:28:05.000000000 +0100
@@ -1,4 +1,4 @@
-VERSION = (1, 7, 1, 'final', 0)
+VERSION = (1, 7, 3, 'final', 0)
 
 
 def get_version(*args, **kwargs):
diff -Nru python-django-1.7.1/django/middleware/csrf.py python-django-1.7.3/django/middleware/csrf.py
--- python-django-1.7.1/django/middleware/csrf.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/middleware/csrf.py	2015-01-13 19:28:05.000000000 +0100
@@ -148,7 +148,11 @@
                 # Barth et al. found that the Referer header is missing for
                 # same-domain requests in only about 0.2% of cases or less, so
                 # we can use strict Referer checking.
-                referer = request.META.get('HTTP_REFERER')
+                referer = force_text(
+                    request.META.get('HTTP_REFERER'),
+                    strings_only=True,
+                    errors='replace'
+                )
                 if referer is None:
                     return self._reject(request, REASON_NO_REFERER)
 
diff -Nru python-django-1.7.1/django/shortcuts.py python-django-1.7.3/django/shortcuts.py
--- python-django-1.7.1/django/shortcuts.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/shortcuts.py	2015-01-13 19:28:05.000000000 +0100
@@ -11,6 +11,8 @@
 from django.db.models.query import QuerySet
 from django.core import urlresolvers
 from django.utils import six
+from django.utils.encoding import force_text
+from django.utils.functional import Promise
 
 
 def render_to_response(*args, **kwargs):
@@ -148,6 +150,11 @@
     if hasattr(to, 'get_absolute_url'):
         return to.get_absolute_url()
 
+    if isinstance(to, Promise):
+        # Expand the lazy instance, as it can cause issues when it is passed
+        # further to some Python functions like urlparse.
+        to = force_text(to)
+
     if isinstance(to, six.string_types):
         # Handle relative URLs
         if any(to.startswith(path) for path in ('./', '../')):
diff -Nru python-django-1.7.1/django/template/base.py python-django-1.7.3/django/template/base.py
--- python-django-1.7.1/django/template/base.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/template/base.py	2015-01-13 19:28:01.000000000 +0100
@@ -17,7 +17,7 @@
 from django.utils.safestring import (SafeData, EscapeData, mark_safe,
     mark_for_escaping)
 from django.utils.formats import localize
-from django.utils.html import escape
+from django.utils.html import conditional_escape
 from django.utils.module_loading import module_has_submodule
 from django.utils import six
 from django.utils.timezone import template_localtime
@@ -881,7 +881,7 @@
     value = force_text(value)
     if ((context.autoescape and not isinstance(value, SafeData)) or
             isinstance(value, EscapeData)):
-        return escape(value)
+        return conditional_escape(value)
     else:
         return value
 
diff -Nru python-django-1.7.1/django/template/debug.py python-django-1.7.3/django/template/debug.py
--- python-django-1.7.1/django/template/debug.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/template/debug.py	2015-01-06 02:20:47.000000000 +0100
@@ -1,6 +1,6 @@
 from django.template.base import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError
 from django.utils.encoding import force_text
-from django.utils.html import escape
+from django.utils.html import conditional_escape
 from django.utils.safestring import SafeData, EscapeData
 from django.utils.formats import localize
 from django.utils.timezone import template_localtime
@@ -98,6 +98,6 @@
                 e.django_template_source = self.source
             raise
         if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData):
-            return escape(output)
+            return conditional_escape(output)
         else:
             return output
diff -Nru python-django-1.7.1/django/template/defaultfilters.py python-django-1.7.3/django/template/defaultfilters.py
--- python-django-1.7.1/django/template/defaultfilters.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/template/defaultfilters.py	2015-01-13 19:28:01.000000000 +0100
@@ -232,9 +232,9 @@
 @stringfilter
 def slugify(value):
     """
-    Converts to lowercase, removes non-word characters (alphanumerics and
-    underscores) and converts spaces to hyphens. Also strips leading and
-    trailing whitespace.
+    Converts to ASCII. Converts spaces to hyphens. Removes characters that
+    aren't alphanumerics, underscores, or hyphens. Converts to lowercase.
+    Also strips leading and trailing whitespace.
     """
     return _slugify(value)
 
diff -Nru python-django-1.7.1/django/utils/datetime_safe.py python-django-1.7.3/django/utils/datetime_safe.py
--- python-django-1.7.1/django/utils/datetime_safe.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/utils/datetime_safe.py	2015-01-06 02:20:47.000000000 +0100
@@ -7,9 +7,9 @@
 # >>> datetime_safe.date(1850, 8, 2).strftime("%Y/%m/%d was a %A")
 # '1850/08/02 was a Friday'
 
-from datetime import date as real_date, datetime as real_datetime
+from datetime import date as real_date, time as real_time, datetime as real_datetime
 import re
-import time
+import time as ttime
 
 
 class date(real_date):
@@ -31,6 +31,10 @@
         return date(self.year, self.month, self.day)
 
 
+class time(real_time):
+    pass
+
+
 def new_date(d):
     "Generate a safe date from a datetime.date object."
     return date(d.year, d.month, d.day)
@@ -80,10 +84,10 @@
     # Move to around the year 2000
     year = year + ((2000 - year) // 28) * 28
     timetuple = dt.timetuple()
-    s1 = time.strftime(fmt, (year,) + timetuple[1:])
+    s1 = ttime.strftime(fmt, (year,) + timetuple[1:])
     sites1 = _findall(s1, str(year))
 
-    s2 = time.strftime(fmt, (year + 28,) + timetuple[1:])
+    s2 = ttime.strftime(fmt, (year + 28,) + timetuple[1:])
     sites2 = _findall(s2, str(year + 28))
 
     sites = []
diff -Nru python-django-1.7.1/django/utils/decorators.py python-django-1.7.3/django/utils/decorators.py
--- python-django-1.7.1/django/utils/decorators.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/utils/decorators.py	2015-01-13 19:28:01.000000000 +0100
@@ -17,7 +17,7 @@
     Converts a function decorator into a method decorator
     """
     # 'func' is a function at the time it is passed to _dec, but will eventually
-    # be a method of the class it is defined it.
+    # be a method of the class it is defined on.
     def _dec(func):
         def _wrapper(self, *args, **kwargs):
             @decorator
diff -Nru python-django-1.7.1/django/utils/html.py python-django-1.7.3/django/utils/html.py
--- python-django-1.7.1/django/utils/html.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/utils/html.py	2015-01-13 19:28:01.000000000 +0100
@@ -36,7 +36,12 @@
 
 def escape(text):
     """
-    Returns the given text with ampersands, quotes and angle brackets encoded for use in HTML.
+    Returns the given text with ampersands, quotes and angle brackets encoded
+    for use in HTML.
+
+    This function always escapes its input, even if it's already escaped and
+    marked as such. This may result in double-escaping. If this is a concern,
+    use conditional_escape() instead.
     """
     return mark_safe(force_text(text).replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;'))
 escape = allow_lazy(escape, six.text_type)
@@ -68,6 +73,9 @@
 def conditional_escape(text):
     """
     Similar to escape(), except that it doesn't operate on pre-escaped strings.
+
+    This function relies on the __html__ convention used both by Django's
+    SafeData class and by third-party libraries like markupsafe.
     """
     if hasattr(text, '__html__'):
         return text.__html__()
diff -Nru python-django-1.7.1/django/utils/http.py python-django-1.7.3/django/utils/http.py
--- python-django-1.7.1/django/utils/http.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/utils/http.py	2015-01-13 19:28:05.000000000 +0100
@@ -272,6 +272,7 @@
     """
     if not url:
         return False
+    url = url.strip()
     # Chrome treats \ completely as /
     url = url.replace('\\', '/')
     # Chrome considers any URL with more than two slashes to be absolute, but
diff -Nru python-django-1.7.1/django/utils/safestring.py python-django-1.7.3/django/utils/safestring.py
--- python-django-1.7.1/django/utils/safestring.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/utils/safestring.py	2015-01-06 02:20:47.000000000 +0100
@@ -36,9 +36,9 @@
 class SafeData(object):
     def __html__(self):
         """
-        Returns the html representation of a string.
+        Returns the html representation of a string for interoperability.
 
-        Allows interoperability with other template engines.
+        This allows other template engines to understand Django's SafeData.
         """
         return self
 
@@ -121,7 +121,7 @@
 
     Can be called multiple times on a single string.
     """
-    if isinstance(s, SafeData):
+    if hasattr(s, '__html__'):
         return s
     if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
         return SafeBytes(s)
@@ -138,10 +138,10 @@
     Can be called multiple times on a single string (the resulting escaping is
     only applied once).
     """
-    if isinstance(s, (SafeData, EscapeData)):
+    if hasattr(s, '__html__') or isinstance(s, EscapeData):
         return s
     if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
         return EscapeBytes(s)
     if isinstance(s, (six.text_type, Promise)):
         return EscapeText(s)
-    return EscapeBytes(bytes(s))
+    return EscapeString(str(s))
diff -Nru python-django-1.7.1/django/utils/six.py python-django-1.7.3/django/utils/six.py
--- python-django-1.7.1/django/utils/six.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/utils/six.py	2015-01-06 02:20:47.000000000 +0100
@@ -1,6 +1,6 @@
 """Utilities for writing code that runs on Python 2 and 3"""
 
-# Copyright (c) 2010-2014 Benjamin Peterson
+# Copyright (c) 2010-2015 Benjamin Peterson
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -20,12 +20,16 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 
+from __future__ import absolute_import
+
+import functools
+import itertools
 import operator
 import sys
 import types
 
 __author__ = "Benjamin Peterson <benjamin@python.org>"
-__version__ = "1.6.1"
+__version__ = "1.9.0"
 
 
 # Useful for very coarse version differentiation.
@@ -83,14 +87,14 @@
         self.name = name
 
     def __get__(self, obj, tp):
-        try:
-            result = self._resolve()
-        except ImportError:
-            # See the nice big comment in MovedModule.__getattr__.
-            raise AttributeError("%s could not be imported " % self.name)
+        result = self._resolve()
         setattr(obj, self.name, result) # Invokes __set__.
-        # This is a bit ugly, but it avoids running this again.
-        delattr(obj.__class__, self.name)
+        try:
+            # This is a bit ugly, but it avoids running this again by
+            # removing this descriptor.
+            delattr(obj.__class__, self.name)
+        except AttributeError:
+            pass
         return result
 
 
@@ -109,22 +113,7 @@
         return _import_module(self.mod)
 
     def __getattr__(self, attr):
-        # It turns out many Python frameworks like to traverse sys.modules and
-        # try to load various attributes. This causes problems if this is a
-        # platform-specific module on the wrong platform, like _winreg on
-        # Unixes. Therefore, we silently pretend unimportable modules do not
-        # have any attributes. See issues #51, #53, #56, and #63 for the full
-        # tales of woe.
-        #
-        # First, if possible, avoid loading the module just to look at __file__,
-        # __name__, or __path__.
-        if (attr in ("__file__", "__name__", "__path__") and
-            self.mod not in sys.modules):
-            raise AttributeError(attr)
-        try:
-            _module = self._resolve()
-        except ImportError:
-            raise AttributeError(attr)
+        _module = self._resolve()
         value = getattr(_module, attr)
         setattr(self, attr, value)
         return value
@@ -170,9 +159,72 @@
         return getattr(module, self.attr)
 
 
+class _SixMetaPathImporter(object):
+    """
+    A meta path importer to import six.moves and its submodules.
+
+    This class implements a PEP302 finder and loader. It should be compatible
+    with Python 2.5 and all existing versions of Python3
+    """
+    def __init__(self, six_module_name):
+        self.name = six_module_name
+        self.known_modules = {}
+
+    def _add_module(self, mod, *fullnames):
+        for fullname in fullnames:
+            self.known_modules[self.name + "." + fullname] = mod
+
+    def _get_module(self, fullname):
+        return self.known_modules[self.name + "." + fullname]
+
+    def find_module(self, fullname, path=None):
+        if fullname in self.known_modules:
+            return self
+        return None
+
+    def __get_module(self, fullname):
+        try:
+            return self.known_modules[fullname]
+        except KeyError:
+            raise ImportError("This loader does not know module " + fullname)
+
+    def load_module(self, fullname):
+        try:
+            # in case of a reload
+            return sys.modules[fullname]
+        except KeyError:
+            pass
+        mod = self.__get_module(fullname)
+        if isinstance(mod, MovedModule):
+            mod = mod._resolve()
+        else:
+            mod.__loader__ = self
+        sys.modules[fullname] = mod
+        return mod
+
+    def is_package(self, fullname):
+        """
+        Return true, if the named module is a package.
+
+        We need this method to get correct spec objects with
+        Python 3.4 (see PEP451)
+        """
+        return hasattr(self.__get_module(fullname), "__path__")
+
+    def get_code(self, fullname):
+        """Return None
+
+        Required, if is_package is implemented"""
+        self.__get_module(fullname)  # eventually raises ImportError
+        return None
+    get_source = get_code  # same as get_code
+
+_importer = _SixMetaPathImporter(__name__)
+
 
 class _MovedItems(_LazyModule):
     """Lazy loading of moved objects"""
+    __path__ = []  # mark as package
 
 
 _moved_attributes = [
@@ -180,11 +232,15 @@
     MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
     MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
     MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
+    MovedAttribute("intern", "__builtin__", "sys"),
     MovedAttribute("map", "itertools", "builtins", "imap", "map"),
     MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
     MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
     MovedAttribute("reduce", "__builtin__", "functools"),
+    MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
     MovedAttribute("StringIO", "StringIO", "io"),
+    MovedAttribute("UserDict", "UserDict", "collections"),
+    MovedAttribute("UserList", "UserList", "collections"),
     MovedAttribute("UserString", "UserString", "collections"),
     MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
     MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
@@ -194,12 +250,14 @@
     MovedModule("configparser", "ConfigParser"),
     MovedModule("copyreg", "copy_reg"),
     MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
+    MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
     MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
     MovedModule("http_cookies", "Cookie", "http.cookies"),
     MovedModule("html_entities", "htmlentitydefs", "html.entities"),
     MovedModule("html_parser", "HTMLParser", "html.parser"),
     MovedModule("http_client", "httplib", "http.client"),
     MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
+    MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
     MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
     MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
     MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
@@ -233,18 +291,19 @@
     MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
     MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
     MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
-    MovedModule("xmlrpc_server", "xmlrpclib", "xmlrpc.server"),
+    MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
     MovedModule("winreg", "_winreg"),
 ]
 for attr in _moved_attributes:
     setattr(_MovedItems, attr.name, attr)
     if isinstance(attr, MovedModule):
-        sys.modules[__name__ + ".moves." + attr.name] = attr
+        _importer._add_module(attr, "moves." + attr.name)
 del attr
 
 _MovedItems._moved_attributes = _moved_attributes
 
-moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves")
+moves = _MovedItems(__name__ + ".moves")
+_importer._add_module(moves, "moves")
 
 
 class Module_six_moves_urllib_parse(_LazyModule):
@@ -268,6 +327,13 @@
     MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
     MovedAttribute("urlencode", "urllib", "urllib.parse"),
     MovedAttribute("splitquery", "urllib", "urllib.parse"),
+    MovedAttribute("splittag", "urllib", "urllib.parse"),
+    MovedAttribute("splituser", "urllib", "urllib.parse"),
+    MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_params", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_query", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
 ]
 for attr in _urllib_parse_moved_attributes:
     setattr(Module_six_moves_urllib_parse, attr.name, attr)
@@ -275,7 +341,8 @@
 
 Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_parse"] = sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse")
+_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
+                      "moves.urllib_parse", "moves.urllib.parse")
 
 
 class Module_six_moves_urllib_error(_LazyModule):
@@ -293,7 +360,8 @@
 
 Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_error"] = sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(__name__ + ".moves.urllib.error")
+_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
+                      "moves.urllib_error", "moves.urllib.error")
 
 
 class Module_six_moves_urllib_request(_LazyModule):
@@ -341,7 +409,8 @@
 
 Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_request"] = sys.modules[__name__ + ".moves.urllib.request"] = Module_six_moves_urllib_request(__name__ + ".moves.urllib.request")
+_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
+                      "moves.urllib_request", "moves.urllib.request")
 
 
 class Module_six_moves_urllib_response(_LazyModule):
@@ -360,7 +429,8 @@
 
 Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_response"] = sys.modules[__name__ + ".moves.urllib.response"] = Module_six_moves_urllib_response(__name__ + ".moves.urllib.response")
+_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
+                      "moves.urllib_response", "moves.urllib.response")
 
 
 class Module_six_moves_urllib_robotparser(_LazyModule):
@@ -376,22 +446,24 @@
 
 Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_robotparser"] = sys.modules[__name__ + ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser")
+_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
+                      "moves.urllib_robotparser", "moves.urllib.robotparser")
 
 
 class Module_six_moves_urllib(types.ModuleType):
     """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
-    parse = sys.modules[__name__ + ".moves.urllib_parse"]
-    error = sys.modules[__name__ + ".moves.urllib_error"]
-    request = sys.modules[__name__ + ".moves.urllib_request"]
-    response = sys.modules[__name__ + ".moves.urllib_response"]
-    robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"]
+    __path__ = []  # mark as package
+    parse = _importer._get_module("moves.urllib_parse")
+    error = _importer._get_module("moves.urllib_error")
+    request = _importer._get_module("moves.urllib_request")
+    response = _importer._get_module("moves.urllib_response")
+    robotparser = _importer._get_module("moves.urllib_robotparser")
 
     def __dir__(self):
         return ['parse', 'error', 'request', 'response', 'robotparser']
 
-
-sys.modules[__name__ + ".moves.urllib"] = Module_six_moves_urllib(__name__ + ".moves.urllib")
+_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
+                      "moves.urllib")
 
 
 def add_move(move):
@@ -418,11 +490,6 @@
     _func_code = "__code__"
     _func_defaults = "__defaults__"
     _func_globals = "__globals__"
-
-    _iterkeys = "keys"
-    _itervalues = "values"
-    _iteritems = "items"
-    _iterlists = "lists"
 else:
     _meth_func = "im_func"
     _meth_self = "im_self"
@@ -432,11 +499,6 @@
     _func_defaults = "func_defaults"
     _func_globals = "func_globals"
 
-    _iterkeys = "iterkeys"
-    _itervalues = "itervalues"
-    _iteritems = "iteritems"
-    _iterlists = "iterlists"
-
 
 try:
     advance_iterator = next
@@ -485,21 +547,49 @@
 get_function_globals = operator.attrgetter(_func_globals)
 
 
-def iterkeys(d, **kw):
-    """Return an iterator over the keys of a dictionary."""
-    return iter(getattr(d, _iterkeys)(**kw))
-
-def itervalues(d, **kw):
-    """Return an iterator over the values of a dictionary."""
-    return iter(getattr(d, _itervalues)(**kw))
-
-def iteritems(d, **kw):
-    """Return an iterator over the (key, value) pairs of a dictionary."""
-    return iter(getattr(d, _iteritems)(**kw))
-
-def iterlists(d, **kw):
-    """Return an iterator over the (key, [values]) pairs of a dictionary."""
-    return iter(getattr(d, _iterlists)(**kw))
+if PY3:
+    def iterkeys(d, **kw):
+        return iter(d.keys(**kw))
+
+    def itervalues(d, **kw):
+        return iter(d.values(**kw))
+
+    def iteritems(d, **kw):
+        return iter(d.items(**kw))
+
+    def iterlists(d, **kw):
+        return iter(d.lists(**kw))
+
+    viewkeys = operator.methodcaller("keys")
+
+    viewvalues = operator.methodcaller("values")
+
+    viewitems = operator.methodcaller("items")
+else:
+    def iterkeys(d, **kw):
+        return iter(d.iterkeys(**kw))
+
+    def itervalues(d, **kw):
+        return iter(d.itervalues(**kw))
+
+    def iteritems(d, **kw):
+        return iter(d.iteritems(**kw))
+
+    def iterlists(d, **kw):
+        return iter(d.iterlists(**kw))
+
+    viewkeys = operator.methodcaller("viewkeys")
+
+    viewvalues = operator.methodcaller("viewvalues")
+
+    viewitems = operator.methodcaller("viewitems")
+
+_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
+_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
+_add_doc(iteritems,
+         "Return an iterator over the (key, value) pairs of a dictionary.")
+_add_doc(iterlists,
+         "Return an iterator over the (key, [values]) pairs of a dictionary.")
 
 
 if PY3:
@@ -520,6 +610,9 @@
     import io
     StringIO = io.StringIO
     BytesIO = io.BytesIO
+    _assertCountEqual = "assertCountEqual"
+    _assertRaisesRegex = "assertRaisesRegex"
+    _assertRegex = "assertRegex"
 else:
     def b(s):
         return s
@@ -532,19 +625,35 @@
         return ord(bs[0])
     def indexbytes(buf, i):
         return ord(buf[i])
-    def iterbytes(buf):
-        return (ord(byte) for byte in buf)
+    iterbytes = functools.partial(itertools.imap, ord)
     import StringIO
     StringIO = BytesIO = StringIO.StringIO
+    _assertCountEqual = "assertItemsEqual"
+    _assertRaisesRegex = "assertRaisesRegexp"
+    _assertRegex = "assertRegexpMatches"
 _add_doc(b, """Byte literal""")
 _add_doc(u, """Text literal""")
 
 
+def assertCountEqual(self, *args, **kwargs):
+    return getattr(self, _assertCountEqual)(*args, **kwargs)
+
+
+def assertRaisesRegex(self, *args, **kwargs):
+    return getattr(self, _assertRaisesRegex)(*args, **kwargs)
+
+
+def assertRegex(self, *args, **kwargs):
+    return getattr(self, _assertRegex)(*args, **kwargs)
+
+
 if PY3:
     exec_ = getattr(moves.builtins, "exec")
 
 
     def reraise(tp, value, tb=None):
+        if value is None:
+            value = tp()
         if value.__traceback__ is not tb:
             raise value.with_traceback(tb)
         raise value
@@ -568,6 +677,21 @@
 """)
 
 
+if sys.version_info[:2] == (3, 2):
+    exec_("""def raise_from(value, from_value):
+    if from_value is None:
+        raise value
+    raise value from from_value
+""")
+elif sys.version_info[:2] > (3, 2):
+    exec_("""def raise_from(value, from_value):
+    raise value from from_value
+""")
+else:
+    def raise_from(value, from_value):
+        raise value
+
+
 print_ = getattr(moves.builtins, "print", None)
 if print_ is None:
     def print_(*args, **kwargs):
@@ -622,54 +746,104 @@
                 write(sep)
             write(arg)
         write(end)
+if sys.version_info[:2] < (3, 3):
+    _print = print_
+    def print_(*args, **kwargs):
+        fp = kwargs.get("file", sys.stdout)
+        flush = kwargs.pop("flush", False)
+        _print(*args, **kwargs)
+        if flush and fp is not None:
+            fp.flush()
 
 _add_doc(reraise, """Reraise an exception.""")
 
+if sys.version_info[0:2] < (3, 4):
+    def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
+              updated=functools.WRAPPER_UPDATES):
+        def wrapper(f):
+            f = functools.wraps(wrapped, assigned, updated)(f)
+            f.__wrapped__ = wrapped
+            return f
+        return wrapper
+else:
+    wraps = functools.wraps
 
 def with_metaclass(meta, *bases):
     """Create a base class with a metaclass."""
-    # This requires a bit of explanation: the basic idea is to make a
-    # dummy metaclass for one level of class instantiation that replaces
-    # itself with the actual metaclass.  Because of internal type checks
-    # we also need to make sure that we downgrade the custom metaclass
-    # for one level to something closer to type (that's why __call__ and
-    # __init__ comes back from type etc.).
+    # This requires a bit of explanation: the basic idea is to make a dummy
+    # metaclass for one level of class instantiation that replaces itself with
+    # the actual metaclass.
     class metaclass(meta):
-        __call__ = type.__call__
-        __init__ = type.__init__
         def __new__(cls, name, this_bases, d):
-            if this_bases is None:
-                return type.__new__(cls, name, (), d)
             return meta(name, bases, d)
-    return metaclass('temporary_class', None, {})
+    return type.__new__(metaclass, 'temporary_class', (), {})
 
 
 def add_metaclass(metaclass):
     """Class decorator for creating a class with a metaclass."""
     def wrapper(cls):
         orig_vars = cls.__dict__.copy()
-        orig_vars.pop('__dict__', None)
-        orig_vars.pop('__weakref__', None)
         slots = orig_vars.get('__slots__')
         if slots is not None:
             if isinstance(slots, str):
                 slots = [slots]
             for slots_var in slots:
                 orig_vars.pop(slots_var)
+        orig_vars.pop('__dict__', None)
+        orig_vars.pop('__weakref__', None)
         return metaclass(cls.__name__, cls.__bases__, orig_vars)
     return wrapper
 
 
+def python_2_unicode_compatible(klass):
+    """
+    A decorator that defines __unicode__ and __str__ methods under Python 2.
+    Under Python 3 it does nothing.
+
+    To support Python 2 and 3 with a single code base, define a __str__ method
+    returning text and apply this decorator to the class.
+    """
+    if PY2:
+        if '__str__' not in klass.__dict__:
+            raise ValueError("@python_2_unicode_compatible cannot be applied "
+                             "to %s because it doesn't define __str__()." %
+                             klass.__name__)
+        klass.__unicode__ = klass.__str__
+        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
+    return klass
+
+
+# Complete the moves implementation.
+# This code is at the end of this module to speed up module loading.
+# Turn this module into a package.
+__path__ = []  # required for PEP 302 and PEP 451
+__package__ = __name__  # see PEP 366 @ReservedAssignment
+if globals().get("__spec__") is not None:
+    __spec__.submodule_search_locations = []  # PEP 451 @UndefinedVariable
+# Remove other six meta path importers, since they cause problems. This can
+# happen if six is removed from sys.modules and then reloaded. (Setuptools does
+# this for some reason.)
+if sys.meta_path:
+    for i, importer in enumerate(sys.meta_path):
+        # Here's some real nastiness: Another "instance" of the six module might
+        # be floating around. Therefore, we can't use isinstance() to check for
+        # the six meta path importer, since the other six instance will have
+        # inserted an importer with different class.
+        if (type(importer).__name__ == "_SixMetaPathImporter" and
+            importer.name == __name__):
+            del sys.meta_path[i]
+            break
+    del i, importer
+# Finally, add the importer to the meta path import hook.
+sys.meta_path.append(_importer)
+
+
 ### Additional customizations for Django ###
 
 if PY3:
-    _assertRaisesRegex = "assertRaisesRegex"
-    _assertRegex = "assertRegex"
     memoryview = memoryview
     buffer_types = (bytes, bytearray, memoryview)
 else:
-    _assertRaisesRegex = "assertRaisesRegexp"
-    _assertRegex = "assertRegexpMatches"
     # memoryview and buffer are not strictly equivalent, but should be fine for
     # django core usage (mainly BinaryField). However, Jython doesn't support
     # buffer (see http://bugs.jython.org/issue1521), so we have to be careful.
@@ -678,15 +852,3 @@
     else:
         memoryview = buffer
     buffer_types = (bytearray, memoryview)
-
-
-def assertRaisesRegex(self, *args, **kwargs):
-    return getattr(self, _assertRaisesRegex)(*args, **kwargs)
-
-
-def assertRegex(self, *args, **kwargs):
-    return getattr(self, _assertRegex)(*args, **kwargs)
-
-
-add_move(MovedModule("_dummy_thread", "dummy_thread"))
-add_move(MovedModule("_thread", "thread"))
diff -Nru python-django-1.7.1/django/utils/text.py python-django-1.7.3/django/utils/text.py
--- python-django-1.7.1/django/utils/text.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/utils/text.py	2015-01-13 19:28:01.000000000 +0100
@@ -435,9 +435,9 @@
 
 def slugify(value):
     """
-    Converts to lowercase, removes non-word characters (alphanumerics and
-    underscores) and converts spaces to hyphens. Also strips leading and
-    trailing whitespace.
+    Converts to ASCII. Converts spaces to hyphens. Removes characters that
+    aren't alphanumerics, underscores, or hyphens. Converts to lowercase.
+    Also strips leading and trailing whitespace.
     """
     value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
     value = re.sub('[^\w\s-]', '', value).strip().lower()
diff -Nru python-django-1.7.1/django/views/static.py python-django-1.7.3/django/views/static.py
--- python-django-1.7.1/django/views/static.py	2014-10-22 18:54:58.000000000 +0200
+++ python-django-1.7.3/django/views/static.py	2015-01-13 19:28:05.000000000 +0100
@@ -17,6 +17,8 @@
 from django.utils.six.moves.urllib.parse import unquote
 from django.utils.translation import ugettext as _, ugettext_lazy
 
+STREAM_CHUNK_SIZE = 4096
+
 
 def serve(request, path, document_root=None, show_indexes=False):
     """
@@ -61,7 +63,8 @@
         return HttpResponseNotModified()
     content_type, encoding = mimetypes.guess_type(fullpath)
     content_type = content_type or 'application/octet-stream'
-    response = StreamingHttpResponse(open(fullpath, 'rb'),
+    f = open(fullpath, 'rb')
+    response = StreamingHttpResponse(iter(lambda: f.read(STREAM_CHUNK_SIZE), b''),
                                      content_type=content_type)
     response["Last-Modified"] = http_date(statobj.st_mtime)
     if stat.S_ISREG(statobj.st_mode):
