diff --git a/circle/acl/management/__init__.py b/circle/acl/management/__init__.py
index 0ee1caf..801c9c3 100644
--- a/circle/acl/management/__init__.py
+++ b/circle/acl/management/__init__.py
@@ -1,24 +1,26 @@
 """
 Creates Levels for all installed apps that have levels.
 """
-from django.db.models import get_models, signals
+from django.db.models import signals
+from django.apps import apps
 from django.db import DEFAULT_DB_ALIAS
 from django.core.exceptions import ImproperlyConfigured
 
 from ..models import Level, AclBase
 
 
-def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
+def create_levels(app_config, verbosity=False, using=DEFAULT_DB_ALIAS,
                   **kwargs):
     """Create and set the weights of the configured Levels.
 
     Based on django.contrib.auth.management.__init__.create_permissions"""
-    # if not router.allow_migrate(db, auth_app.Permission):
+    # if not router.allow_migrate(using, auth_app.Permission):
     #    return
 
     from django.contrib.contenttypes.models import ContentType
 
-    app_models = [k for k in get_models(app) if AclBase in k.__bases__]
+    app_models = [k for k in apps.get_models(app_config)
+                  if AclBase in k.__bases__]
     print "Creating levels for models: %s." % ", ".join(
         [m.__name__ for m in app_models])
 
@@ -31,7 +33,7 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
     for klass in app_models:
         # Force looking up the content types in the current database
         # before creating foreign keys to them.
-        ctype1 = ContentType.objects.db_manager(db).get_for_model(klass)
+        ctype1 = ContentType.objects.db_manager(using).get_for_model(klass)
         ctypes.add(ctype1)
         weight = 0
         try:
@@ -46,7 +48,7 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
     # Find all the Levels that have a content_type for a model we're
     # looking for.  We don't need to check for codenames since we already have
     # a list of the ones we're going to create.
-    all_levels = set(Level.objects.using(db).filter(
+    all_levels = set(Level.objects.using(using).filter(
         content_type__in=ctypes,
     ).values_list(
         "content_type", "codename"
@@ -57,7 +59,7 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
         for ctype, (codename, name) in searched_levels
         if (ctype.pk, codename) not in all_levels
     ]
-    Level.objects.using(db).bulk_create(levels)
+    Level.objects.using(using).bulk_create(levels)
     if verbosity >= 2:
         print("Adding levels [%s]." % ", ".join(unicode(l) for l in levels))
         print("Searched: [%s]." % ", ".join(
@@ -70,5 +72,5 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
                              content_type=ctype).update(weight=weight)
 
 
-signals.post_syncdb.connect(
+signals.post_migrate.connect(
     create_levels, dispatch_uid="circle.acl.management.create_levels")
diff --git a/circle/acl/models.py b/circle/acl/models.py
index 590857a..109a03a 100644
--- a/circle/acl/models.py
+++ b/circle/acl/models.py
@@ -18,7 +18,7 @@
 import logging
 
 from django.contrib.auth.models import User, Group
-from django.contrib.contenttypes.generic import (
+from django.contrib.contenttypes.fields import (
     GenericForeignKey, GenericRelation
 )
 from django.contrib.contenttypes.models import ContentType
diff --git a/circle/circle/__init__.py b/circle/circle/__init__.py
index b2279b4..d7f6581 100644
--- a/circle/circle/__init__.py
+++ b/circle/circle/__init__.py
@@ -12,9 +12,10 @@ def update_permissions_after_migration(sender, **kwargs):
     """
 
     from django.conf import settings
-    from django.db.models import get_models
+    from django.apps import apps
     from django.contrib.auth.management import create_permissions
 
-    create_permissions(sender, get_models(), 2 if settings.DEBUG else 0)
+    create_permissions(sender, apps.get_models(), 2 if settings.DEBUG else 0)
+
 
 post_migrate.connect(update_permissions_after_migration)
diff --git a/circle/circle/settings/base.py b/circle/circle/settings/base.py
index 8600b77..65b1c04 100644
--- a/circle/circle/settings/base.py
+++ b/circle/circle/settings/base.py
@@ -166,96 +166,95 @@ if exists(p):
     STATICFILES_DIRS.append(p)
 
 STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
-PIPELINE_COMPILERS = (
-    'pipeline.compilers.less.LessCompiler',
-)
-PIPELINE_CSS_COMPRESSOR = 'pipeline.compressors.yuglify.YuglifyCompressor'
-# PIPELINE_JS_COMPRESSOR = 'pipeline.compressors.slimit.SlimItCompressor'
-PIPELINE_JS_COMPRESSOR = None
-PIPELINE_DISABLE_WRAPPER = True
-PIPELINE_LESS_ARGUMENTS = u'--include-path={}'.format(':'.join(STATICFILES_DIRS))
-PIPELINE_CSS = {
-    "all": {"source_filenames": (
-        "compile_bootstrap.less",
-        "bootstrap/dist/css/bootstrap-theme.css",
-        "fontawesome/css/font-awesome.css",
-        "jquery-simple-slider/css/simple-slider.css",
-        "intro.js/introjs.css",
-        "template.less",
-        "dashboard/dashboard.less",
-        "network/network.less",
-        "autocomplete_light/style.css",
-    ),
-        "output_filename": "all.css",
-    }
-}
-PIPELINE_JS = {
-    "all": {"source_filenames": (
-        # "jquery/dist/jquery.js",  # included separately
-        "bootbox/bootbox.js",
-        "bootstrap/dist/js/bootstrap.js",
-        "intro.js/intro.js",
-        "jquery-knob/dist/jquery.knob.min.js",
-        "jquery-simple-slider/js/simple-slider.js",
-        "favico.js/favico.js",
-        "datatables/media/js/jquery.dataTables.js",
-        "dashboard/dashboard.js",
-        "dashboard/activity.js",
-        "dashboard/group-details.js",
-        "dashboard/group-list.js",
-        "dashboard/js/stupidtable.min.js",  # no bower file
-        "dashboard/node-create.js",
-        "dashboard/node-details.js",
-        "dashboard/node-list.js",
-        "dashboard/profile.js",
-        "dashboard/store.js",
-        "dashboard/template-list.js",
-        "dashboard/vm-common.js",
-        "dashboard/vm-create.js",
-        "dashboard/vm-list.js",
-        "dashboard/help.js",
-        "js/host.js",
-        "js/network.js",
-        "js/switch-port.js",
-        "js/host-list.js",
-        "autocomplete_light/autocomplete.js",
-        "autocomplete_light/widget.js",
-        "autocomplete_light/addanother.js",
-        "autocomplete_light/text_widget.js",
-        "autocomplete_light/remote.js",
-    ),
-        "output_filename": "all.js",
-    },
-    "vm-detail": {"source_filenames": (
-        "clipboard/dist/clipboard.min.js",
-        "dashboard/vm-details.js",
-        "no-vnc/include/util.js",
-        "no-vnc/include/webutil.js",
-        "no-vnc/include/base64.js",
-        "no-vnc/include/websock.js",
-        "no-vnc/include/des.js",
-        "no-vnc/include/keysym.js",
-        "no-vnc/include/keysymdef.js",
-        "no-vnc/include/keyboard.js",
-        "no-vnc/include/input.js",
-        "no-vnc/include/display.js",
-        "no-vnc/include/jsunzip.js",
-        "no-vnc/include/rfb.js",
-        "dashboard/vm-console.js",
-        "dashboard/vm-tour.js",
-    ),
-        "output_filename": "vm-detail.js",
+
+PIPELINE = {
+    'COMPILERS' : ('pipeline.compilers.less.LessCompiler',),
+    'LESS_ARGUMENTS': u'--include-path={}'.format(':'.join(STATICFILES_DIRS)),
+    'CSS_COMPRESSOR': 'pipeline.compressors.yuglify.YuglifyCompressor',
+    'JS_COMPRESSOR': None,
+    'DISABLE_WRAPPER': True,
+    'STYLESHEETS': {
+        "all": {"source_filenames": (
+            "compile_bootstrap.less",
+            "bootstrap/dist/css/bootstrap-theme.css",
+            "fontawesome/css/font-awesome.css",
+            "jquery-simple-slider/css/simple-slider.css",
+            "intro.js/introjs.css",
+            "template.less",
+            "dashboard/dashboard.less",
+            "network/network.less",
+            "autocomplete_light/vendor/select2/dist/css/select2.css",
+            "autocomplete_light/select2.css",
+        ),
+            "output_filename": "all.css",
+        }
     },
-    "datastore": {"source_filenames": (
-        "chart.js/dist/Chart.min.js",
-        "dashboard/datastore-details.js"
-    ),
-        "output_filename": "datastore.js",
+    'JAVASCRIPT': {
+        "all": {"source_filenames": (
+            # "jquery/dist/jquery.js",  # included separately
+            "bootbox/bootbox.js",
+            "bootstrap/dist/js/bootstrap.js",
+            "intro.js/intro.js",
+            "jquery-knob/dist/jquery.knob.min.js",
+            "jquery-simple-slider/js/simple-slider.js",
+            "favico.js/favico.js",
+            "datatables/media/js/jquery.dataTables.js",
+            "autocomplete_light/jquery.init.js",
+            "autocomplete_light/autocomplete.init.js",
+            "autocomplete_light/vendor/select2/dist/js/select2.js",
+            "autocomplete_light/select2.js",
+            "dashboard/dashboard.js",
+            "dashboard/activity.js",
+            "dashboard/group-details.js",
+            "dashboard/group-list.js",
+            "dashboard/js/stupidtable.min.js",  # no bower file
+            "dashboard/node-create.js",
+            "dashboard/node-details.js",
+            "dashboard/node-list.js",
+            "dashboard/profile.js",
+            "dashboard/store.js",
+            "dashboard/template-list.js",
+            "dashboard/vm-common.js",
+            "dashboard/vm-create.js",
+            "dashboard/vm-list.js",
+            "dashboard/help.js",
+            "js/host.js",
+            "js/network.js",
+            "js/switch-port.js",
+            "js/host-list.js",
+        ),
+            "output_filename": "all.js",
+        },
+        "vm-detail": {"source_filenames": (
+            "clipboard/dist/clipboard.min.js",
+            "dashboard/vm-details.js",
+            "no-vnc/include/util.js",
+            "no-vnc/include/webutil.js",
+            "no-vnc/include/base64.js",
+            "no-vnc/include/websock.js",
+            "no-vnc/include/des.js",
+            "no-vnc/include/keysym.js",
+            "no-vnc/include/keysymdef.js",
+            "no-vnc/include/keyboard.js",
+            "no-vnc/include/input.js",
+            "no-vnc/include/display.js",
+            "no-vnc/include/jsunzip.js",
+            "no-vnc/include/rfb.js",
+            "dashboard/vm-console.js",
+            "dashboard/vm-tour.js",
+        ),
+            "output_filename": "vm-detail.js",
+        },
+        "datastore": {"source_filenames": (
+            "chart.js/dist/Chart.min.js",
+            "dashboard/datastore-details.js"
+        ),
+            "output_filename": "datastore.js",
+        },
     },
 }
 
 
-
 ########## SECRET CONFIGURATION
 # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
 # Note: This key should only be used for development and testing.
@@ -279,26 +278,31 @@ FIXTURE_DIRS = (
 
 
 ########## TEMPLATE CONFIGURATION
-# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
-TEMPLATE_CONTEXT_PROCESSORS = (
-    'django.contrib.auth.context_processors.auth',
-    'django.core.context_processors.debug',
-    'django.core.context_processors.i18n',
-    'django.core.context_processors.media',
-    'django.core.context_processors.static',
-    'django.core.context_processors.tz',
-    'django.contrib.messages.context_processors.messages',
-    'django.core.context_processors.request',
-    'dashboard.context_processors.notifications',
-    'dashboard.context_processors.extract_settings',
-    'dashboard.context_processors.broadcast_messages',
-)
 
-# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
-TEMPLATE_DIRS = (
-    normpath(join(SITE_ROOT, '../../site-circle/templates')),
-    normpath(join(SITE_ROOT, 'templates')),
-)
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#TEMPLATES
+TEMPLATES = [{
+    'BACKEND': 'django.template.backends.django.DjangoTemplates',
+    'DIRS' : (
+        normpath(join(SITE_ROOT, '../../site-circle/templates')),
+        normpath(join(SITE_ROOT, 'templates')),
+    ),
+    'APP_DIRS': True,
+    'OPTIONS': {
+        'context_processors': (
+            'django.contrib.auth.context_processors.auth',
+            'django.template.context_processors.debug',
+            'django.template.context_processors.i18n',
+            'django.template.context_processors.media',
+            'django.template.context_processors.static',
+            'django.template.context_processors.tz',
+            'django.contrib.messages.context_processors.messages',
+            'django.template.context_processors.request',
+            'dashboard.context_processors.notifications',
+            'dashboard.context_processors.extract_settings',
+            'dashboard.context_processors.broadcast_messages',
+        ),
+    },
+}]
 ########## END TEMPLATE CONFIGURATION
 
 
@@ -336,6 +340,10 @@ DJANGO_APPS = (
     # Useful template tags:
     # 'django.contrib.humanize',
 
+    # Django autocomplete light
+    # it needs registering before django admin
+    'dal',
+    'dal_select2',
     # Admin panel and documentation:
     'django.contrib.admin',
     # 'django.contrib.admindocs',
@@ -348,7 +356,6 @@ THIRD_PARTY_APPS = (
     'taggit',
     'statici18n',
     'django_sshkey',
-    'autocomplete_light',
     'pipeline',
 )
 
diff --git a/circle/circle/settings/local.py b/circle/circle/settings/local.py
index 96f2322..cc5b2ae 100644
--- a/circle/circle/settings/local.py
+++ b/circle/circle/settings/local.py
@@ -27,7 +27,7 @@ from base import *  # noqa
 DEBUG = True
 
 # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
-TEMPLATE_DEBUG = DEBUG
+TEMPLATES[0]['OPTIONS']['debug'] = DEBUG
 ########## END DEBUG CONFIGURATION
 
 SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
@@ -110,8 +110,10 @@ if DEBUG:
     from django.dispatch import Signal
     Signal.send_robust = Signal.send
 
-PIPELINE_COMPILERS = (
+PIPELINE["COMPILERS"] = (
     'dashboard.compilers.DummyLessCompiler',
 )
 
 ADMIN_ENABLED = True
+
+ALLOWED_HOSTS = ['*']
diff --git a/circle/circle/settings/selenium_test.py b/circle/circle/settings/selenium_test.py
index aaaeb54..5966f36 100644
--- a/circle/circle/settings/selenium_test.py
+++ b/circle/circle/settings/selenium_test.py
@@ -14,9 +14,10 @@
 #
 # You should have received a copy of the GNU General Public License along
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
+
 import os
 
-from .base import *  # noqa
+from .base import *  # flake8:noqa
 
 
 # fix https://github.com/django-nose/django-nose/issues/197
diff --git a/circle/circle/settings/test.py b/circle/circle/settings/test.py
index a4dd668..a44b068 100644
--- a/circle/circle/settings/test.py
+++ b/circle/circle/settings/test.py
@@ -38,7 +38,11 @@ INSTALLED_APPS += (
     'django_nose',
 )
 TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
-NOSE_ARGS = ['--with-doctest', '--exclude-dir=dashboard/tests/selenium']
+NOSE_ARGS = [
+    '--with-doctest',
+    '--exclude-dir=dashboard/tests/selenium',
+    '--exclude=circle'
+]
 PASSWORD_HASHERS = ['django.contrib.auth.hashers.MD5PasswordHasher']
 
 CACHES = {
@@ -59,7 +63,7 @@ for i in LOCAL_APPS:
 
 # don't print SQL queries
 LOGGING['handlers']['null'] = {'level': "DEBUG",
-                               'class': "django.utils.log.NullHandler"}
+                               'class': "logging.NullHandler"}
 LOGGING['loggers']['django.db.backends'] = {
     'handlers': ['null'],
     'propagate': False,
diff --git a/circle/circle/urls.py b/circle/circle/urls.py
index 0130af6..a9a81bc 100644
--- a/circle/circle/urls.py
+++ b/circle/circle/urls.py
@@ -15,13 +15,16 @@
 # You should have received a copy of the GNU General Public License along
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
-from django.conf.urls import patterns, include, url
+from django.conf.urls import include, url
 from django.views.generic import TemplateView
 
 from django.conf import settings
 from django.contrib import admin
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
+from django.contrib.auth.views import (
+    password_reset_confirm, password_reset
+)
 
 
 from circle.settings.base import get_env_variable
@@ -33,9 +36,7 @@ from firewall.views import add_blacklist_item
 
 admin.autodiscover()
 
-urlpatterns = patterns(
-    '',
-
+urlpatterns = [
     url(r'^$', lambda x: redirect(reverse("dashboard.index"))),
     url(r'^network/', include('network.urls')),
     url(r'^blacklist-add/', add_blacklist_item),
@@ -45,12 +46,11 @@ urlpatterns = patterns(
     # django/contrib/auth/urls.py (care when new version)
     url((r'^accounts/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/'
          r'(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$'),
-        'django.contrib.auth.views.password_reset_confirm',
+        password_reset_confirm,
         {'set_password_form': CircleSetPasswordForm},
         name='accounts.password_reset_confirm'
         ),
-    url(r'^accounts/password/reset/$', ("django.contrib.auth.views."
-                                        "password_reset"),
+    url(r'^accounts/password/reset/$', password_reset,
         {'password_reset_form': CirclePasswordResetForm},
         name="accounts.password-reset",
         ),
@@ -73,27 +73,24 @@ urlpatterns = patterns(
         name="info.support"),
     url(r'^info/resize-how-to/$', ResizeHelpView.as_view(),
         name="info.resize"),
-)
+]
 
 
 if 'rosetta' in settings.INSTALLED_APPS:
-    urlpatterns += patterns(
-        '',
+    urlpatterns += [
         url(r'^rosetta/', include('rosetta.urls')),
-    )
+    ]
 
 if settings.ADMIN_ENABLED:
-    urlpatterns += patterns(
-        '',
+    urlpatterns += [
         url(r'^admin/', include(admin.site.urls)),
-    )
+    ]
 
 
 if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
-    urlpatterns += patterns(
-        '',
+    urlpatterns += [
         (r'^saml2/', include('djangosaml2.urls')),
-    )
+    ]
 
 handler500 = 'common.views.handler500'
 handler403 = 'common.views.handler403'
diff --git a/circle/common/views.py b/circle/common/views.py
index 5a6a3a2..9613d94 100644
--- a/circle/common/views.py
+++ b/circle/common/views.py
@@ -45,7 +45,8 @@ def handler500(request):
     logger.exception("unhandled exception")
     ctx = get_context(request, exception)
     try:
-        resp = render_to_response("500.html", ctx, RequestContext(request))
+        resp = render_to_response("500.html", ctx,
+                                  RequestContext(request).flatten())
     except:
         resp = render_to_response("500.html", ctx)
     resp.status_code = 500
diff --git a/circle/dashboard/forms.py b/circle/dashboard/forms.py
index d1a0330..23cca74 100644
--- a/circle/dashboard/forms.py
+++ b/circle/dashboard/forms.py
@@ -31,7 +31,7 @@ from django.contrib.auth.models import User, Group
 from django.core.validators import URLValidator
 from django.core.exceptions import PermissionDenied, ValidationError
 
-import autocomplete_light
+from dal import autocomplete
 from crispy_forms.helper import FormHelper
 from crispy_forms.layout import (
     Layout, Div, BaseInput, Field, HTML, Submit, TEMPLATE_PACK, Fieldset
@@ -43,7 +43,6 @@ from crispy_forms.bootstrap import FormActions
 from django import forms
 from django.contrib.auth.forms import UserCreationForm as OrgUserCreationForm
 from django.forms.widgets import TextInput, HiddenInput
-from django.template import Context
 from django.template.loader import render_to_string
 from django.utils.html import escape, format_html
 from django.utils.safestring import mark_safe
@@ -67,6 +66,7 @@ from .validators import domain_validator
 
 from dashboard.models import ConnectCommand, create_profile
 
+
 LANGUAGES_WITH_CODE = ((l[0], string_concat(l[1], " (", l[0], ")"))
                        for l in LANGUAGES)
 
@@ -1180,8 +1180,7 @@ class AnyTag(Div):
             fields += render_field(field, form, form_style, context,
                                    template_pack=template_pack)
 
-        return render_to_string(self.template, Context({'tag': self,
-                                                        'fields': fields}))
+        return render_to_string(self.template, {'tag': self, 'fields': fields})
 
 
 class WorkingBaseInput(BaseInput):
@@ -1334,27 +1333,31 @@ class UserEditForm(forms.ModelForm):
 
 
 class AclUserOrGroupAddForm(forms.Form):
-    name = forms.CharField(widget=autocomplete_light.TextWidget(
-        'AclUserGroupAutocomplete',
-        attrs={'class': 'form-control',
-               'placeholder': _("Name of group or user")}))
+    name = forms.CharField(
+        widget=autocomplete.ListSelect2(
+            url='autocomplete.acl.user-group',
+            attrs={'class': 'form-control',
+                   'data-html': 'true',
+                   'data-placeholder': _("Name of group or user")}))
 
 
 class TransferOwnershipForm(forms.Form):
     name = forms.CharField(
-        widget=autocomplete_light.TextWidget(
-            'AclUserAutocomplete',
+        widget=autocomplete.ListSelect2(
+            url='autocomplete.acl.user',
             attrs={'class': 'form-control',
-                   'placeholder': _("Name of user")}),
+                   'data-html': 'true',
+                   'data-placeholder': _("Name of user")}),
         label=_("E-mail address or identifier of user"))
 
 
 class AddGroupMemberForm(forms.Form):
     new_member = forms.CharField(
-        widget=autocomplete_light.TextWidget(
-            'AclUserAutocomplete',
+        widget=autocomplete.ListSelect2(
+            url='autocomplete.acl.user',
             attrs={'class': 'form-control',
-                   'placeholder': _("Name of user")}),
+                   'data-html': 'true',
+                   'data-placeholder': _("Name of user")}),
         label=_("E-mail address or identifier of user"))
 
 
diff --git a/circle/dashboard/management/commands/init.py b/circle/dashboard/management/commands/init.py
index 7efd9e5..34d4dcc 100644
--- a/circle/dashboard/management/commands/init.py
+++ b/circle/dashboard/management/commands/init.py
@@ -18,7 +18,6 @@
 from __future__ import unicode_literals, absolute_import
 
 import logging
-from optparse import make_option
 
 from django.contrib.auth.models import User
 from django.core.management.base import BaseCommand
@@ -32,19 +31,18 @@ logger = logging.getLogger(__name__)
 
 
 class Command(BaseCommand):
-    option_list = BaseCommand.option_list + (
-        make_option('--force', action="store_true"),
-        make_option('--external-net'),
-        make_option('--management-net'),
-        make_option('--vm-net'),
-        make_option('--external-if'),
-        make_option('--management-if'),
-        make_option('--vm-if'),
-        make_option('--datastore-queue'),
-        make_option('--firewall-queue'),
-        make_option('--admin-user'),
-        make_option('--admin-pass'),
-    )
+    def add_arguments(self, parser):
+        parser.add_argument('--force', action="store_true")
+        parser.add_argument('--external-net')
+        parser.add_argument('--management-net')
+        parser.add_argument('--vm-net')
+        parser.add_argument('--external-if')
+        parser.add_argument('--management-if')
+        parser.add_argument('--vm-if')
+        parser.add_argument('--datastore-queue')
+        parser.add_argument('--firewall-queue')
+        parser.add_argument('--admin-user')
+        parser.add_argument('--admin-pass')
 
     def create(self, model, field, **kwargs):
         value = kwargs[field]
@@ -59,14 +57,15 @@ class Command(BaseCommand):
 
 # http://docs.saltstack.com/en/latest/ref/states/all/salt.states.cmd.html
     def print_state(self):
-        print "\nchanged=%s" % ("yes" if self.changed else "no")
+        self.stdout.write("\nchanged=%s" % ("yes" if self.changed else "no"))
 
     def handle(self, *args, **options):
         self.changed = False
 
         if (DataStore.objects.exists() and Vlan.objects.exists() and
                 not options['force']):
-            return self.print_state()
+            self.print_state()
+            return
 
         admin = self.create(User, 'username', username=options['admin_user'],
                             is_superuser=True, is_staff=True)
@@ -153,4 +152,4 @@ class Command(BaseCommand):
                     direction='out', action='accept',
                     foreign_network=vg_net, vlan=man)
 
-        return self.print_state()
+        self.print_state()
diff --git a/circle/dashboard/migrations/0006_auto_20170707_1909.py b/circle/dashboard/migrations/0006_auto_20170707_1909.py
new file mode 100644
index 0000000..cbc4e20
--- /dev/null
+++ b/circle/dashboard/migrations/0006_auto_20170707_1909.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.3 on 2017-07-07 19:09
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dashboard', '0005_profile_two_factor_secret'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='connectcommand',
+            name='name',
+            field=models.CharField(help_text='Name of your custom command.', max_length=128, verbose_name='name'),
+        ),
+    ]
diff --git a/circle/dashboard/models.py b/circle/dashboard/models.py
index a906763..2050590 100644
--- a/circle/dashboard/models.py
+++ b/circle/dashboard/models.py
@@ -151,7 +151,7 @@ class ConnectCommand(Model):
     access_method = CharField(max_length=10, choices=ACCESS_METHODS,
                               verbose_name=_('access method'),
                               help_text=_('Type of the remote access method.'))
-    name = CharField(max_length="128", verbose_name=_('name'), blank=False,
+    name = CharField(max_length=128, verbose_name=_('name'), blank=False,
                      help_text=_("Name of your custom command."))
     template = CharField(blank=True, null=True, max_length=256,
                          verbose_name=_('command template'),
diff --git a/circle/dashboard/static/dashboard/dashboard.js b/circle/dashboard/static/dashboard/dashboard.js
index f2c65df..4db99a6 100644
--- a/circle/dashboard/static/dashboard/dashboard.js
+++ b/circle/dashboard/static/dashboard/dashboard.js
@@ -508,13 +508,6 @@ $.ajaxSetup({
   }
 });
 
-/* for autocomplete */
-$(function() {
-  yourlabs.TextWidget.prototype.getValue = function(choice) {
-    return choice.children().html();
-  };
-});
-
 var tagsToReplace = {
     '&': '&amp;',
     '<': '&lt;',
diff --git a/circle/dashboard/static/dashboard/dashboard.less b/circle/dashboard/static/dashboard/dashboard.less
index 548ad83..3c0447f 100644
--- a/circle/dashboard/static/dashboard/dashboard.less
+++ b/circle/dashboard/static/dashboard/dashboard.less
@@ -1031,7 +1031,7 @@ textarea[name="new_members"] {
   font-weight: bold;
 }
 
-.hilight .autocomplete-hl {
+.select2-results__option--highlighted .autocomplete-hl {
   color: orange;
 }
 
diff --git a/circle/dashboard/templates/dashboard/_manage_access.html b/circle/dashboard/templates/dashboard/_manage_access.html
index 99190ed..fca5542 100644
--- a/circle/dashboard/templates/dashboard/_manage_access.html
+++ b/circle/dashboard/templates/dashboard/_manage_access.html
@@ -24,7 +24,7 @@
         <td>
             <select class="form-control" name="perm-u-{{i.user.id}}"{% if i.level not in acl.allowed_levels %} disabled{% endif %}>
             {% for id, name in acl.levels %}
-            <option{%if id = i.level%} selected="selected"{%endif%}
+            <option{%if id == i.level%} selected="selected"{%endif%}
             {% if id not in acl.allowed_levels %} disabled{% endif %}
                 value="{{id}}">{{name}}</option>
             {% endfor %}
@@ -46,7 +46,7 @@
         <td>
             <select class="form-control" name="perm-g-{{i.group.id}}{% if i.level not in acl.allowed_levels %} disabled{% endif %}">
             {% for id, name in acl.levels %}
-            <option{%if id = i.level%} selected="selected"{%endif%}
+            <option{%if id == i.level%} selected="selected"{%endif%}
             {% if id not in acl.allowed_levels %} disabled{% endif %}
                 value="{{id}}">{{name}}</option>
             {% endfor %}
diff --git a/circle/dashboard/templates/dashboard/group-detail.html b/circle/dashboard/templates/dashboard/group-detail.html
index 19119d9..54b194b 100644
--- a/circle/dashboard/templates/dashboard/group-detail.html
+++ b/circle/dashboard/templates/dashboard/group-detail.html
@@ -137,8 +137,10 @@
         {% if user.is_superuser %}
           <hr />
 
-          <script type="text/javascript" src="/static/admin/js/jquery.min.js"></script>
-          <script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
+          <script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.min.js"></script>
+          <script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>      
+          <script type="text/javascript" src="/static/autocomplete_light/jquery.init.js"></script>
+          <script type="text/javascript" src="/static/autocomplete_light/vendor/select2/dist/js/select2.js"></script>
           {{ group_perm_form.media }}
 
           <h3>{% trans "Group permissions" %}</h3>
diff --git a/circle/dashboard/templates/dashboard/lease-edit.html b/circle/dashboard/templates/dashboard/lease-edit.html
index 03c282e..bda8c8b 100644
--- a/circle/dashboard/templates/dashboard/lease-edit.html
+++ b/circle/dashboard/templates/dashboard/lease-edit.html
@@ -52,7 +52,7 @@
                 <td>
                   <select class="form-control" name="perm-u-{{i.user.id}}">
                     {% for id, name in acl.levels %}
-                    <option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
+                    <option{%if id == i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
                     {% endfor %}
                   </select>
                 </td>
@@ -72,7 +72,7 @@
                 <td>
                   <select class="form-control" name="perm-g-{{i.group.id}}">
                     {% for id, name in acl.levels %}
-                    <option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
+                    <option{%if id == i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
                     {% endfor %}
                   </select>
                 </td>
diff --git a/circle/dashboard/templates/django_tables2/table_no_page.html b/circle/dashboard/templates/django_tables2/table_no_page.html
index 866a81a..c6281bf 100644
--- a/circle/dashboard/templates/django_tables2/table_no_page.html
+++ b/circle/dashboard/templates/django_tables2/table_no_page.html
@@ -4,9 +4,9 @@
 {% if table.page %}
 <div class="table-container">
 {% endif %}
+{% endspaceless %}
 {% block table %}
 <table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
-    {% nospaceless %}
     {% block table.thead %}
     <thead>
         <tr>
@@ -42,10 +42,9 @@
     {% block table.tfoot %}
     <tfoot></tfoot>
     {% endblock table.tfoot %}
-    {% endnospaceless %}
 </table>
 {% endblock table %}
-
+{% spaceless %}
 {% if table.page %}
 </div>
 {% endif %}
diff --git a/circle/dashboard/tests/test_mockedviews.py b/circle/dashboard/tests/test_mockedviews.py
index 511edbd..adb38fd 100644
--- a/circle/dashboard/tests/test_mockedviews.py
+++ b/circle/dashboard/tests/test_mockedviews.py
@@ -21,7 +21,7 @@ import warnings
 from factory import Factory, Sequence
 from mock import patch, MagicMock
 
-from django.contrib.auth.models import User
+from django.contrib.auth.models import User, AnonymousUser
 from django.core.exceptions import PermissionDenied
 from django.core.signing import TimestampSigner, JSONSerializer, b64_encode
 from django.http import HttpRequest, Http404, QueryDict
@@ -629,13 +629,13 @@ def FakeRequestFactory(user=None, **kwargs):
     '''
 
     if user is None:
-        user = UserFactory()
         auth = kwargs.pop('authenticated', True)
-        user.is_authenticated = lambda: auth
+        user = UserFactory() if auth else AnonymousUser()
         user.is_superuser = kwargs.pop('superuser', False)
         if kwargs.pop('has_perms_mock', False):
             user.has_perms = MagicMock(return_value=True)
-        user.save()
+        if auth:
+            user.save()
 
     request = HttpRequest()
     request.user = user
diff --git a/circle/dashboard/tests/test_templates.py b/circle/dashboard/tests/test_templates.py
index c6a356e..370aa36 100644
--- a/circle/dashboard/tests/test_templates.py
+++ b/circle/dashboard/tests/test_templates.py
@@ -29,22 +29,22 @@ class TemplateSyntaxTestCase(unittest.TestCase):
     def test_templates(self):
         """Test all templates for syntax errors."""
         for loader in Engine.get_default().template_loaders:
-            print loader
+            print(loader)
             self._test_dir(loader.get_template_sources(''))
 
     def _test_dir(self, dir, path="/"):
         for i in dir:
-            i = join(path, i)
+            i = join(path, str(i))
             if isfile(i):
                 self._test_template(join(path, i))
             elif isdir(i):
-                print "%s:" % i
+                print("%s:" % i)
                 self._test_dir(listdir(i), i)
 
     def _test_template(self, path):
-        print path
+        print(path)
         try:
             Template(open(path).read()).render(Context({}))
         except (NoReverseMatch, VariableDoesNotExist, KeyError, AttributeError,
                 ValueError, ) as e:
-            print e
+            print(e)
diff --git a/circle/dashboard/tests/test_views.py b/circle/dashboard/tests/test_views.py
index e0389b6..f77157e 100644
--- a/circle/dashboard/tests/test_views.py
+++ b/circle/dashboard/tests/test_views.py
@@ -1902,9 +1902,9 @@ class TwoFactorTest(LoginMixin, TestCase):
         response = c.get("/two-factor-login/", follow=True)
         self.assertItemsEqual(
             response.redirect_chain,
-            [('http://testserver/', 302),
-             ('http://testserver/dashboard/', 302),
-             ('http://testserver/accounts/login/?next=/dashboard/', 302)]
+            [('/', 302),
+             ('/dashboard/', 302),
+             ('/accounts/login/?next=/dashboard/', 302)]
         )
 
     def test_straight_to_2fa_as_user(self):
@@ -1913,6 +1913,6 @@ class TwoFactorTest(LoginMixin, TestCase):
         response = c.get("/two-factor-login/", follow=True)
         self.assertItemsEqual(
             response.redirect_chain,
-            [('http://testserver/', 302),
-             ('http://testserver/dashboard/', 302)]
+            [('/', 302),
+             ('/dashboard/', 302)]
         )
diff --git a/circle/dashboard/urls.py b/circle/dashboard/urls.py
index ab0fa2e..d465676 100644
--- a/circle/dashboard/urls.py
+++ b/circle/dashboard/urls.py
@@ -16,9 +16,8 @@
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
 from __future__ import absolute_import
-from django.conf.urls import patterns, url, include
+from django.conf.urls import url
 
-import autocomplete_light
 from vm.models import Instance
 from .views import (
     AclUpdateView, FavouriteView, GroupAclUpdateView, GroupDelete,
@@ -56,14 +55,13 @@ from .views import (
     StorageDetail, DiskDetail,
     MessageList, MessageDetail, MessageCreate, MessageDelete,
     EnableTwoFactorView, DisableTwoFactorView,
+    AclUserGroupAutocomplete, AclUserAutocomplete,
 )
 from .views.vm import vm_ops, vm_mass_ops
 from .views.node import node_ops
 
-autocomplete_light.autodiscover()
 
-urlpatterns = patterns(
-    '',
+urlpatterns = [
     url(r'^$', IndexView.as_view(), name="dashboard.index"),
     url(r"^profile/list/$", UserList.as_view(),
         name="dashboard.views.user-list"),
@@ -217,8 +215,6 @@ urlpatterns = patterns(
         ConnectCommandCreate.as_view(),
         name="dashboard.views.connect-command-create"),
 
-    url(r'^autocomplete/', include('autocomplete_light.urls')),
-
     url(r"^store/list/$", StoreList.as_view(),
         name="dashboard.views.store-list"),
     url(r"^store/download/$", store_download,
@@ -253,22 +249,26 @@ urlpatterns = patterns(
         name="dashboard.views.message-create"),
     url(r'^message/delete/(?P<pk>\d+)/$', MessageDelete.as_view(),
         name="dashboard.views.message-delete"),
-)
 
-urlpatterns += patterns(
-    '',
-    *(url(r'^vm/(?P<pk>\d+)/op/%s/$' % op, v.as_view(), name=v.get_urlname())
-        for op, v in vm_ops.iteritems())
-)
+    url(r'^autocomplete/acl/user-group/$',
+        AclUserGroupAutocomplete.as_view(),
+        name='autocomplete.acl.user-group'),
+    url(r'^autocomplete/acl/user/$',
+        AclUserAutocomplete.as_view(),
+        name='autocomplete.acl.user'),
+]
 
-urlpatterns += patterns(
-    '',
-    *(url(r'^vm/mass_op/%s/$' % op, v.as_view(), name=v.get_urlname())
-        for op, v in vm_mass_ops.iteritems())
-)
+urlpatterns += [
+    url(r'^vm/(?P<pk>\d+)/op/%s/$' % op, v.as_view(), name=v.get_urlname())
+    for op, v in vm_ops.iteritems()
+]
 
-urlpatterns += patterns(
-    '',
-    *(url(r'^node/(?P<pk>\d+)/op/%s/$' % op, v.as_view(), name=v.get_urlname())
-        for op, v in node_ops.iteritems())
-)
+urlpatterns += [
+    url(r'^vm/mass_op/%s/$' % op, v.as_view(), name=v.get_urlname())
+    for op, v in vm_mass_ops.iteritems()
+]
+
+urlpatterns += [
+    url(r'^node/(?P<pk>\d+)/op/%s/$' % op, v.as_view(), name=v.get_urlname())
+    for op, v in node_ops.iteritems()
+]
diff --git a/circle/dashboard/views/__init__.py b/circle/dashboard/views/__init__.py
index f799d8d..13af4ac 100644
--- a/circle/dashboard/views/__init__.py
+++ b/circle/dashboard/views/__init__.py
@@ -15,3 +15,4 @@ from graph import *
 from storage import *
 from request import *
 from message import *
+from autocomplete import *
diff --git a/circle/dashboard/autocomplete_light_registry.py b/circle/dashboard/views/autocomplete.py
similarity index 63%
rename from circle/dashboard/autocomplete_light_registry.py
rename to circle/dashboard/views/autocomplete.py
index 47e5d8e..be6984b 100644
--- a/circle/dashboard/autocomplete_light_registry.py
+++ b/circle/dashboard/views/autocomplete.py
@@ -15,13 +15,16 @@
 # You should have received a copy of the GNU General Public License along
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
-import autocomplete_light
+import json
+from dal import autocomplete
 from django.contrib.auth.models import User
 from django.utils.html import escape
 from django.utils.translation import ugettext as _
+from django.db.models import Q
+from django.http import HttpResponse
 
-from .views import AclUpdateView
-from .models import Profile
+from ..views import AclUpdateView
+from ..models import Profile
 
 
 def highlight(field, q, none_wo_match=True):
@@ -48,13 +51,21 @@ def highlight(field, q, none_wo_match=True):
         return escape(field)
 
 
-class AclUserGroupAutocomplete(autocomplete_light.AutocompleteGenericBase):
-    search_fields = (
-        ('first_name', 'last_name', 'username', 'email', 'profile__org_id'),
-        ('name', 'groupprofile__org_id'),
-    )
-    choice_html_format = (u'<span data-value="%s"><span style="display:none"'
-                          u'>%s</span>%s</span>')
+class AclUserAutocomplete(autocomplete.Select2ListView):
+    search_fields = ('first_name', 'last_name', 'username',
+                     'email', 'profile__org_id')
+
+    def filter(self, qs, search_fields):
+        if self.q:
+            condition = Q()
+            for field in search_fields:
+                condition |= Q(**{field + '__icontains': unicode(self.q)})
+            return list(qs.filter(condition))
+        return []
+
+    def get_list(self):
+        users = AclUpdateView.get_allowed_users(self.request.user)
+        return self.filter(users, self.search_fields)
 
     def choice_displayed_text(self, choice):
         q = unicode(self.request.GET.get('q', ''))
@@ -71,35 +82,17 @@ class AclUserGroupAutocomplete(autocomplete_light.AutocompleteGenericBase):
         else:
             return _('%s (group)') % name
 
-    def choice_html(self, choice):
-        return self.choice_html_format % (
-            self.choice_value(choice), self.choice_label(choice),
-            self.choice_displayed_text(choice))
-
-    def choices_for_request(self):
-        user = self.request.user
-        self.choices = (AclUpdateView.get_allowed_users(user),
-                        AclUpdateView.get_allowed_groups(user))
-        return super(AclUserGroupAutocomplete, self).choices_for_request()
-
-    def autocomplete_html(self):
-        html = []
-
-        for choice in self.choices_for_request():
-            html.append(self.choice_html(choice))
-
-        if not html:
-            html = self.empty_html_format % _('no matches found').capitalize()
-
-        return self.autocomplete_html_format % ''.join(html)
-
+    def get(self, *args, **kwargs):
+        return HttpResponse(json.dumps({
+            'results': [dict(id=unicode(r), text=self.choice_displayed_text(r))
+                        for r in self.get_list()]
+        }), content_type="application/json")
 
-class AclUserAutocomplete(AclUserGroupAutocomplete):
-    def choices_for_request(self):
-        user = self.request.user
-        self.choices = (AclUpdateView.get_allowed_users(user), )
-        return super(AclUserGroupAutocomplete, self).choices_for_request()
 
+class AclUserGroupAutocomplete(AclUserAutocomplete):
+    group_search_fields = ('name', 'groupprofile__org_id')
 
-autocomplete_light.register(AclUserGroupAutocomplete)
-autocomplete_light.register(AclUserAutocomplete)
+    def get_list(self):
+        groups = AclUpdateView.get_allowed_groups(self.request.user)
+        groups = self.filter(groups, self.group_search_fields)
+        return super(AclUserGroupAutocomplete, self).get_list() + groups
diff --git a/circle/dashboard/views/graph.py b/circle/dashboard/views/graph.py
index 07593ab..eadbffe 100644
--- a/circle/dashboard/views/graph.py
+++ b/circle/dashboard/views/graph.py
@@ -171,6 +171,7 @@ class TemplateVms(object):
     def get_minmax(self):
         return (0, None)
 
+
 register_graph(TemplateVms, 'instances', TemplateGraphView)
 
 
@@ -197,6 +198,7 @@ class Ram(object):
     def get_minmax(self):
         return (0, 105)
 
+
 register_graph(Ram, 'memory', VmGraphView)
 register_graph(Ram, 'memory', NodeGraphView)
 
@@ -212,6 +214,7 @@ class Cpu(object):
         else:
             return (0, self.obj.num_cores * 100 + 5)
 
+
 register_graph(Cpu, 'cpu', VmGraphView)
 register_graph(Cpu, 'cpu', NodeGraphView)
 
@@ -236,6 +239,7 @@ class VmNetwork(object):
                     params))
         return 'group(%s)' % ','.join(metrics) if metrics else None
 
+
 register_graph(VmNetwork, 'network', VmGraphView)
 
 
@@ -251,6 +255,7 @@ class NodeNetwork(object):
             '10), ".*\.bytes_(sent|recv)-([a-zA-Z0-9]+).*", "\\2 \\1")' % (
                 self.obj.metric_prefix))
 
+
 register_graph(NodeNetwork, 'network', NodeGraphView)
 
 
@@ -262,6 +267,7 @@ class NodeVms(object):
     def get_minmax(self):
         return (0, None)
 
+
 register_graph(NodeVms, 'vm', NodeGraphView)
 
 
@@ -282,6 +288,7 @@ class NodeAllocated(object):
     def get_minmax(self):
         return (0, None)
 
+
 register_graph(NodeAllocated, 'alloc', NodeGraphView)
 
 
@@ -302,6 +309,7 @@ class NodeListAllocated(object):
     def get_minmax(self):
         return (0, None)
 
+
 register_graph(NodeListAllocated, 'alloc', NodeListGraphView)
 
 
@@ -315,4 +323,5 @@ class NodeListVms(object):
     def get_minmax(self):
         return (0, None)
 
+
 register_graph(NodeListVms, 'vm', NodeListGraphView)
diff --git a/circle/dashboard/views/index.py b/circle/dashboard/views/index.py
index 24d964d..d125de7 100644
--- a/circle/dashboard/views/index.py
+++ b/circle/dashboard/views/index.py
@@ -18,7 +18,7 @@ from __future__ import unicode_literals, absolute_import
 
 import logging
 
-from django.core.cache import get_cache
+from django.core.cache import cache
 from django.core.urlresolvers import reverse
 from django.conf import settings
 from django.contrib.auth.models import Group, User
@@ -103,7 +103,6 @@ class IndexView(LoginRequiredMixin, TemplateView):
         # toplist
         if settings.STORE_URL:
             cache_key = "files-%d" % self.request.user.pk
-            cache = get_cache("default")
             files = cache.get(cache_key)
             if not files:
                 try:
diff --git a/circle/dashboard/views/node.py b/circle/dashboard/views/node.py
index 3fed127..7561f5c 100644
--- a/circle/dashboard/views/node.py
+++ b/circle/dashboard/views/node.py
@@ -27,7 +27,6 @@ from django.db.models import Count
 from django.forms.models import inlineformset_factory
 from django.http import HttpResponse
 from django.shortcuts import redirect
-from django.template import RequestContext
 from django.template.loader import render_to_string
 from django.utils.translation import ugettext as _
 from django.views.generic import DetailView, TemplateView, View
@@ -330,8 +329,12 @@ class NodeActivityView(LoginRequiredMixin, SuperuserRequiredMixin, View):
         response = {
             'activities': render_to_string(
                 "dashboard/node-detail/_activity-timeline.html",
-                RequestContext(request, {'activities': activities,
-                                         'show_show_all': show_show_all}))
+                {
+                    'activities': activities,
+                    'show_show_all': show_show_all
+                },
+                request
+            )
         }
 
         return HttpResponse(
diff --git a/circle/dashboard/views/store.py b/circle/dashboard/views/store.py
index d7acf3c..be26d41 100644
--- a/circle/dashboard/views/store.py
+++ b/circle/dashboard/views/store.py
@@ -24,12 +24,11 @@ from django.conf import settings
 from django.contrib import messages
 from django.contrib.auth.decorators import login_required
 from django.template.defaultfilters import urlencode
-from django.core.cache import get_cache
+from django.core.cache import cache
 from django.core.exceptions import SuspiciousOperation
 from django.core.urlresolvers import reverse
 from django.http import HttpResponse
 from django.shortcuts import redirect, render_to_response, render
-from django.template import RequestContext
 from django.utils.translation import ugettext as _
 from django.views.decorators.http import require_GET, require_POST
 from django.views.generic import TemplateView
@@ -65,7 +64,7 @@ class StoreList(LoginRequiredMixin, TemplateView):
                 context = self.get_context_data(**kwargs)
                 return render_to_response(
                     "dashboard/store/_list-box.html",
-                    RequestContext(self.request, context),
+                    context, self.request
                 )
             else:
                 return super(StoreList, self).get(*args, **kwargs)
@@ -193,7 +192,6 @@ def store_new_directory(request):
 @login_required
 def store_refresh_toplist(request):
     cache_key = "files-%d" % request.user.pk
-    cache = get_cache("default")
     try:
         store = Store(request.user)
         toplist = store.toplist()
diff --git a/circle/dashboard/views/user.py b/circle/dashboard/views/user.py
index 0e78b4b..120bdbd 100644
--- a/circle/dashboard/views/user.py
+++ b/circle/dashboard/views/user.py
@@ -231,7 +231,7 @@ class MyPreferencesView(UpdateView):
     def get(self, request, form=None, *args, **kwargs):
         # if this is not here, it won't work
         self.object = self.get_object()
-        context = self.get_context_data(*args, **kwargs)
+        context = self.get_context_data(form=form, *args, **kwargs)
         if form is not None:
             # a little cheating, users can't post invalid
             # language selection forms (without modifying the HTML)
diff --git a/circle/dashboard/views/vm.py b/circle/dashboard/views/vm.py
index 20c706c..294223a 100644
--- a/circle/dashboard/views/vm.py
+++ b/circle/dashboard/views/vm.py
@@ -32,7 +32,6 @@ from django.http import (
     HttpResponse, Http404, HttpResponseRedirect, JsonResponse
 )
 from django.shortcuts import redirect, get_object_or_404
-from django.template import RequestContext
 from django.template.loader import render_to_string
 from django.utils.translation import (
     ugettext as _, ugettext_noop, ungettext_lazy,
@@ -1289,15 +1288,15 @@ def vm_activity(request, pk):
 
     response['activities'] = render_to_string(
         "dashboard/vm-detail/_activity-timeline.html",
-        RequestContext(request, context),
+        context, request
     )
     response['ops'] = render_to_string(
         "dashboard/vm-detail/_operations.html",
-        RequestContext(request, context),
+        context, request
     )
     response['disk_ops'] = render_to_string(
         "dashboard/vm-detail/_disk-operations.html",
-        RequestContext(request, context),
+        context, request
     )
 
     return HttpResponse(
diff --git a/circle/firewall/admin.py b/circle/firewall/admin.py
index 87a5e28..6d88e73 100644
--- a/circle/firewall/admin.py
+++ b/circle/firewall/admin.py
@@ -143,6 +143,7 @@ class SwitchPortAdmin(admin.ModelAdmin):
 class EthernetDeviceAdmin(admin.ModelAdmin):
     list_display = ('name', )
 
+
 admin.site.register(Host, HostAdmin)
 admin.site.register(Vlan, VlanAdmin)
 admin.site.register(Rule, RuleAdmin)
diff --git a/circle/firewall/fields.py b/circle/firewall/fields.py
index 8f93b33..c6ed7fb 100644
--- a/circle/firewall/fields.py
+++ b/circle/firewall/fields.py
@@ -52,12 +52,19 @@ class MACAddressFormField(forms.Field):
 
 class MACAddressField(models.Field):
     description = _('MAC Address object')
-    __metaclass__ = models.SubfieldBase
 
     def __init__(self, *args, **kwargs):
         kwargs['max_length'] = 17
         super(MACAddressField, self).__init__(*args, **kwargs)
 
+    def deconstruct(self):
+        name, path, args, kwargs = super(MACAddressField, self).deconstruct()
+        del kwargs['max_length']
+        return name, path, args, kwargs
+
+    def from_db_value(self, value, expression, connection, context):
+        return self.to_python(value)
+
     def to_python(self, value):
         if not value:
             return None
@@ -105,16 +112,25 @@ class IPAddressFormField(forms.Field):
 
 class IPAddressField(models.Field):
     description = _('IP Network object')
-    __metaclass__ = models.SubfieldBase
 
     def __init__(self, version=4, serialize=True, *args, **kwargs):
         kwargs['max_length'] = 100
         self.version = version
         super(IPAddressField, self).__init__(*args, **kwargs)
 
+    def deconstruct(self):
+        name, path, args, kwargs = super(IPAddressField, self).deconstruct()
+        del kwargs['max_length']
+        if self.version != 4:
+            kwargs['version'] = self.version
+        return name, path, args, kwargs
+
     def get_internal_type(self):
         return "CharField"
 
+    def from_db_value(self, value, expression, connection, context):
+        return self.to_python(value)
+
     def to_python(self, value):
         if not value:
             return None
@@ -163,13 +179,22 @@ class IPNetworkFormField(forms.Field):
 
 class IPNetworkField(models.Field):
     description = _('IP Network object')
-    __metaclass__ = models.SubfieldBase
 
     def __init__(self, version=4, serialize=True, *args, **kwargs):
         kwargs['max_length'] = 100
         self.version = version
         super(IPNetworkField, self).__init__(*args, **kwargs)
 
+    def deconstruct(self):
+        name, path, args, kwargs = super(IPNetworkField, self).deconstruct()
+        del kwargs['max_length']
+        if self.version != 4:
+            kwargs['version'] = self.version
+        return name, path, args, kwargs
+
+    def from_db_value(self, value, expression, connection, context):
+        return self.to_python(value)
+
     def to_python(self, value):
         if not value:
             return None
diff --git a/circle/firewall/fw.py b/circle/firewall/fw.py
index 2cec2f4..ce21f57 100644
--- a/circle/firewall/fw.py
+++ b/circle/firewall/fw.py
@@ -25,7 +25,7 @@ from .models import (Host, Rule, Vlan, Domain, Record, BlacklistItem,
                      SwitchPort)
 from .iptables import IptRule, IptChain
 import django.conf
-from django.template import loader, Context
+from django.template import loader
 from django.utils import timezone
 
 
@@ -152,9 +152,9 @@ class BuildFirewall:
 
         template = loader.get_template('firewall/iptables.conf')
         context['proto'] = 'ipv4'
-        ipv4 = unicode(template.render(Context(context)))
+        ipv4 = unicode(template.render(context))
         context['proto'] = 'ipv6'
-        ipv6 = unicode(template.render(Context(context)))
+        ipv6 = unicode(template.render(context))
         return (ipv4, ipv6)
 
 
diff --git a/circle/firewall/migrations/0006_auto_20170707_1909.py b/circle/firewall/migrations/0006_auto_20170707_1909.py
new file mode 100644
index 0000000..3973a85
--- /dev/null
+++ b/circle/firewall/migrations/0006_auto_20170707_1909.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.3 on 2017-07-07 19:09
+from __future__ import unicode_literals
+
+from django.db import migrations
+import firewall.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('firewall', '0005_auto_20150520_2250'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='host',
+            name='ipv6',
+            field=firewall.fields.IPAddressField(blank=True, help_text='The global IPv6 address of the host, for example 2001:db:88:200::10.', null=True, unique=True, verbose_name='IPv6 address', version=6),
+        ),
+        migrations.AlterField(
+            model_name='vlan',
+            name='network6',
+            field=firewall.fields.IPNetworkField(blank=True, help_text='The IPv6 address and the prefix length of the gateway.', null=True, verbose_name='IPv6 address/prefix', version=6),
+        ),
+    ]
diff --git a/circle/firewall/tests/test_firewall.py b/circle/firewall/tests/test_firewall.py
index 4e9a035..f037bcd 100644
--- a/circle/firewall/tests/test_firewall.py
+++ b/circle/firewall/tests/test_firewall.py
@@ -80,7 +80,7 @@ class GetNewAddressTestCase(MockCeleryMixin, TestCase):
         self.vlan = Vlan(vid=1, name='test', network4='10.0.0.1/29',
                          network6='2001:738:2001:4031::/80', domain=d,
                          owner=self.u1)
-        self.vlan.clean()
+        self.vlan.full_clean()
         self.vlan.save()
         self.vlan.host_set.all().delete()
         for i in range(3, 6):
diff --git a/circle/network/urls.py b/circle/network/urls.py
index dc13f31..cdedbbf 100644
--- a/circle/network/urls.py
+++ b/circle/network/urls.py
@@ -15,7 +15,7 @@
 # You should have received a copy of the GNU General Public License along
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
-from django.conf.urls import patterns, url
+from django.conf.urls import url
 from .views import (
     IndexView,
     HostList, HostDetail, HostCreate, HostDelete,
@@ -33,8 +33,7 @@ from .views import (
     VlanAclUpdateView
 )
 
-urlpatterns = patterns(
-    '',
+urlpatterns = [
     url('^$', IndexView.as_view(), name='network.index'),
     # blacklist
     url('^blacklist/$', BlacklistList.as_view(),
@@ -135,4 +134,4 @@ urlpatterns = patterns(
         remove_switch_port_device, name='network.remove_switch_port_device'),
     url('^switchports/(?P<pk>\d+)/add/$', add_switch_port_device,
         name='network.add_switch_port_device'),
-)
+]
diff --git a/circle/request/forms.py b/circle/request/forms.py
index 443d0b3..587cc7e 100644
--- a/circle/request/forms.py
+++ b/circle/request/forms.py
@@ -19,7 +19,6 @@ from django.forms import (
     Textarea, ValidationError
 )
 from django.utils.translation import ugettext_lazy as _
-from django.template import RequestContext
 from django.template.loader import render_to_string
 
 from sizefield.widgets import FileSizeWidget
@@ -68,8 +67,7 @@ class InitialFromFileMixin(object):
         super(InitialFromFileMixin, self).__init__(*args, **kwargs)
 
         self.initial['message'] = render_to_string(
-            self.initial_template,
-            RequestContext(request, {}),
+            self.initial_template, {}, request
         )
 
     def clean_message(self):
diff --git a/circle/request/urls.py b/circle/request/urls.py
index c69aa8d..7bf5cf5 100644
--- a/circle/request/urls.py
+++ b/circle/request/urls.py
@@ -16,7 +16,7 @@
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
 from __future__ import absolute_import
-from django.conf.urls import patterns, url
+from django.conf.urls import url
 
 from .views import (
     RequestList, RequestDetail, RequestTypeList,
@@ -26,8 +26,7 @@ from .views import (
     LeaseTypeDelete, TemplateAccessTypeDelete, ResizeRequestView,
 )
 
-urlpatterns = patterns(
-    '',
+urlpatterns = [
     url(r'^list/$', RequestList.as_view(),
         name="request.views.request-list"),
     url(r'^(?P<pk>\d+)/$', RequestDetail.as_view(),
@@ -62,4 +61,4 @@ urlpatterns = patterns(
         name="request.views.request-resource"),
     url(r'resize/(?P<vm_pk>\d+)/(?P<disk_pk>\d+)/$',
         ResizeRequestView.as_view(), name="request.views.request-resize"),
-)
+]
diff --git a/circle/vm/__init__.py b/circle/vm/__init__.py
index 62e09b9..4ede8e6 100644
--- a/circle/vm/__init__.py
+++ b/circle/vm/__init__.py
@@ -1,2 +1 @@
-# This import is responsible for running the operations' registration code.
-from . import operations  # noqa
+# noqa
diff --git a/circle/vm/tests/test_models.py b/circle/vm/tests/test_models.py
index 65e24be..5442280 100644
--- a/circle/vm/tests/test_models.py
+++ b/circle/vm/tests/test_models.py
@@ -177,9 +177,9 @@ class InterfaceTestCase(MockCeleryMixin, TestCase):
         i = Instance(id=10, owner=owner, access_method='rdp')
         d = Domain(owner=owner)
         d.save()
-        v = Vlan(vid=55, network4='127.0.0.1/8',
+        v = Vlan(name='vlan', vid=55, network4='127.0.0.1/8',
                  network6='2001::1/32', domain=d)
-        v.clean()
+        v.full_clean()
         v.save()
         Interface.create(i, v, managed=True, owner=owner)
 
diff --git a/requirements/base.txt b/requirements/base.txt
index 683880e..6ea96b1 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -4,18 +4,19 @@ arrow==0.7.0
 billiard==3.3.0.20
 bpython==0.14.1
 celery==3.1.18
-Django==1.8.15
-django-appconf==1.0.1
-django-autocomplete-light==2.1.1
-django-braces==1.8.0
-django-crispy-forms==1.6.0
-django-model-utils==2.2
-djangosaml2==0.13.0
-django-sizefield==0.7
+Django==1.11.3
+django-appconf==1.0.2
+django-autocomplete-light==3.2.9
+django-braces==1.11.0
+django-crispy-forms==1.6.1
+django-model-utils==3.0.0
+django-pipeline==1.6.13
+django-sizefield==0.9.1
+django-statici18n==1.4.0
+django-tables2==1.10.0
+django-taggit==0.22.1
+djangosaml2==0.16.0
 git+https://git.ik.bme.hu/circle/django-sshkey.git
-django-statici18n==1.1.3
-django-tables2==0.16.0
-django-taggit==0.14.0
 docutils==0.12
 Jinja2==2.7.3
 jsonfield==1.0.3
@@ -39,6 +40,6 @@ six==1.9.0
 slimit==0.8.1
 sqlparse==0.1.15
 pika==0.9.14
-django-pipeline==1.4.7
 Fabric==1.10.1
 lxml==3.4.4
+python-memcached==1.58
\ No newline at end of file
diff --git a/requirements/local.txt b/requirements/local.txt
index db1a4c2..f24d055 100644
--- a/requirements/local.txt
+++ b/requirements/local.txt
@@ -1,6 +1,6 @@
 # Local development dependencies go here
 -r base.txt
 coverage==3.7.1
-django-debug-toolbar==1.3.0
-django-rosetta==0.7.6
+django-debug-toolbar==1.8
+django-rosetta==0.7.13
 Sphinx==1.3.1
diff --git a/requirements/test.txt b/requirements/test.txt
index 247ee04..5075ee3 100644
--- a/requirements/test.txt
+++ b/requirements/test.txt
@@ -3,9 +3,9 @@
 coverage==3.7.1
 factory-boy==2.4.1
 mock==1.0.1
-django-nose==1.4
-nose==1.3.6
-nose-exclude==0.2.0
+django-nose==1.4.4
+nose==1.3.7
+nose-exclude==0.5.0
 selenium==2.45.0
 selenose==1.3
 -e git+https://github.com/kmmbvnr/django-jenkins.git@019774dc2f668bc66b66f90f97eb8e14ae9566a4#egg=django_jenkins-dev