CORD-2723 upgrade to django 1.11

Change-Id: I8150124a6e44e03319edbd518a53c7ab207a9238
diff --git a/containers/xos/pip_requirements.txt b/containers/xos/pip_requirements.txt
index a5ccc8e..8032632 100644
--- a/containers/xos/pip_requirements.txt
+++ b/containers/xos/pip_requirements.txt
@@ -1,7 +1,7 @@
-pytz==2017.2
+pytz==2018.3
 sphinx==1.3.1
 Babel==2.3.4
-Django==1.8.18
+Django==1.11.10
 Jinja2==2.9.6
 Markdown==2.6.8
 MarkupSafe==1.0
@@ -31,13 +31,11 @@
 cryptography==1.9
 debtcollector==1.8.0
 decorator==4.1.2
-django-bitfield==1.8.0
-django-encrypted-fields==1.1.2
-django-extensions==1.7.3
-django-filter==0.14.0
-django-ipware==1.1.5
+django-extensions==1.9.9
+django-filter==1.1.0
+django-ipware==2.0.1
 django-timezones==0.2
-djangorestframework==3.3.3
+djangorestframework==3.7.7
 dnslib==0.9.6
 docutils==0.13.1
 docker-compose==1.9.0
diff --git a/xos/core/context_processors.py b/xos/core/context_processors.py
deleted file mode 100644
index 5de751f..0000000
--- a/xos/core/context_processors.py
+++ /dev/null
@@ -1,35 +0,0 @@
-
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-from django.conf import settings
-from core.models import Site
-
-
-def xos(request):
-    allSites = []
-    for site in Site.objects.all():
-        allowNewUsers = True    # replace with logic for blessing sites for registration, if necessary
-        allSites.append( {"name": site.name,
-                           "id": site.id,
-                           "allowNewUsers": allowNewUsers} )
-
-    return {"DISABLE_MINIDASHBOARD": settings.DISABLE_MINIDASHBOARD,
-            "XOS_BRANDING_NAME": settings.XOS_BRANDING_NAME,
-            "XOS_BRANDING_CSS": settings.XOS_BRANDING_CSS,
-            "XOS_BRANDING_ICON": settings.XOS_BRANDING_ICON,
-            "XOS_BRANDING_FAVICON": settings.XOS_BRANDING_FAVICON,
-            "XOS_BRANDING_BG": settings.XOS_BRANDING_BG,
-            "sites": allSites}
diff --git a/xos/core/models/attic/xosbase_header.py b/xos/core/models/attic/xosbase_header.py
index 0923c04..8afc3f0 100644
--- a/xos/core/models/attic/xosbase_header.py
+++ b/xos/core/models/attic/xosbase_header.py
@@ -31,6 +31,7 @@
 from django.core.exceptions import PermissionDenied
 from cgi import escape as html_escape
 from django.db.models.deletion import Collector
+from django.db.models.query import QuerySet
 from django.db import router
 from django.contrib.contenttypes.models import ContentType
 
@@ -44,12 +45,18 @@
 
 XOS_GLOBAL_DEFAULT_SECURITY_POLICY = True
 
-def date_handler(obj):
+def json_handler(obj):
     if isinstance(obj, pytz.tzfile.DstTzInfo):
         # json can't serialize DstTzInfo
         return str(obj)
     elif hasattr(obj, 'timetuple'):
         return calendar.timegm(obj.timetuple())
+    elif isinstance(obj, QuerySet):
+        # django 1.11.0 - model_to_dict() turns reverse foreign relations into querysets
+        return [x.id for x in obj]
+    elif isinstance(obj, Model):
+        # django 1.11.10 - model_to_dict() turns reverse foreign relations into lists of models
+        return obj.id
     else:
         return obj
 
@@ -271,7 +278,7 @@
                 json_dict['deleted'] = True
                 json_dict['object'] = {'id': pk}
 
-            payload = json.dumps(json_dict, default=date_handler)
+            payload = json.dumps(json_dict, default=json_handler)
             r.publish(self.__class__.__name__, payload)
         except ConnectionError:
             # Redis not running.
diff --git a/xos/core/models/user.py b/xos/core/models/user.py
index 47c69e2..1268fc5 100644
--- a/xos/core/models/user.py
+++ b/xos/core/models/user.py
@@ -23,6 +23,7 @@
 from core.middleware import get_request
 from xosbase import XOSBase, PlModelMixIn
 from core.models.xosbase import StrippedCharField, XOSCollector
+from django.conf import settings
 from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
 from django.core.exceptions import PermissionDenied
 from django.core.mail import EmailMultiAlternatives
@@ -32,7 +33,6 @@
 from django.db.models import F, Q
 from django.forms.models import model_to_dict
 from django.utils import timezone
-from timezones.fields import TimeZoneField
 from django.contrib.contenttypes.models import ContentType
 
 # The following manual import is needed because we do not
@@ -162,7 +162,7 @@
     no_sync = models.BooleanField(default=False)     # prevent object sync
     no_policy = models.BooleanField(default=False)   # prevent model_policy run
 
-    timezone = TimeZoneField()
+    timezone = models.CharField(max_length=100, null=True, blank=True, default=settings.TIME_ZONE)
 
     leaf_model_name = models.CharField( help_text = "The most specialized model in this chain of inheritance, often defined by a service developer", max_length = 1024, null = False )
 
diff --git a/xos/coreapi/reaper.py b/xos/coreapi/reaper.py
index 25fb226..75f75b2 100644
--- a/xos/coreapi/reaper.py
+++ b/xos/coreapi/reaper.py
@@ -34,6 +34,7 @@
     os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
 
 from datetime import datetime
+import django
 from django.db import reset_queries
 from django.db.models import F, Q
 from django.db.models.signals import post_save
@@ -117,7 +118,7 @@
             # Reap non-sync'd models here
             # models_to_reap = [Slice,Network,NetworkSlice]
 
-            models_to_reap = django_models.get_models(include_auto_created=False)
+            models_to_reap = django.apps.apps.get_models(include_auto_created=False)
             for m in models_to_reap:
                 if not hasattr(m, "deleted_objects"):
                     continue
@@ -143,21 +144,14 @@
                         log.info('REAPER: cannot purge object because its cascade_set is nonempty',object = d, cascade_set = ",".join([str(m) for m in cascade_set]))
                         continue
 
-#                    XXX I don't think we need dependency_walker here anymore,
-#                    XXX since the cascade set would include any inverse
-#                    XXX dependencies automatically.
-#                    deps = walk_inv_deps(noop, d)
-#                    if (not deps):
-
-                    if (True):
-                        self.journal_object(d, "reaper.purge")
-                        log.info('REAPER: purging object',object = d)
-                        try:
-                            d.delete(purge=True)
-                        except:
-                            self.journal_object(d, "reaper.purge.exception")
-                            log.error('REAPER: exception purging object', object = d)
-                            traceback.print_exc()
+                    self.journal_object(d, "reaper.purge")
+                    log.info('REAPER: purging object',object = d)
+                    try:
+                        d.delete(purge=True)
+                    except:
+                        self.journal_object(d, "reaper.purge.exception")
+                        log.error('REAPER: exception purging object', object = d)
+                        traceback.print_exc()
             try:
                 reset_queries()
             except:
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index 9b8b6e8..57ffec1 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -14,7 +14,6 @@
 # limitations under the License.
 
 
-from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
 from django import VERSION as DJANGO_VERSION
 import socket
 import os
@@ -181,12 +180,6 @@
         if line:
             INSTALLED_APPS = list(INSTALLED_APPS) + [line]
 
-# Added for django-suit form
-TEMPLATE_CONTEXT_PROCESSORS = TCP + (
-    'django.core.context_processors.request',
-    'core.context_processors.xos',
-)
-
 # A sample logging configuration. The only tangible logging
 # performed by this configuration is to send an email to
 # the site admins on every HTTP 500 error when DEBUG=False.
diff --git a/xos/xos/urls.py b/xos/xos/urls.py
index dd6ca87..6ed5c28 100644
--- a/xos/xos/urls.py
+++ b/xos/xos/urls.py
@@ -15,40 +15,7 @@
 
 
 import importlib
-from django.conf.urls import patterns, include, url
-
 from core.models import *
-from rest_framework import generics
-from django.http import HttpResponseRedirect
 
-def load_class(full_class_string):
-    """
-    dynamically load a class from a string
-    """
-
-    class_data = full_class_string.split(".")
-    module_path = ".".join(class_data[:-1])
-    class_str = class_data[-1]
-
-    module = importlib.import_module(module_path)
-    # Finally, we retrieve the Class
-    return getattr(module, class_str)
-
-def redirect_to_apache(request):
-    """ bounce a request back to the apache server that is running on the machine """
-    apache_url = "http://%s%s" % (request.META['HOSTNAME'], request.path)
-    return HttpResponseRedirect(apache_url)
-
-urlpatterns = patterns(
-    '',
-    # Is this necessary?
-    url(r'^files/', redirect_to_apache),
-
-    # Adding in rest_framework urls
-    url(r'^xos/', include('rest_framework.urls', namespace='rest_framework')),
-
-    # handcrafted API methods
-    # NOTE: Needs to stay until Tosca switchover is complete
-    url(r'^', include('api.import_methods', namespace='api')),
-  )
+urlpatterns = []