Skip to main content

Python Django: How to Resolve "ImportError: Cannot Import Name 'six' from 'django.utils'"

If you've recently upgraded Django to version 3.0 or later, you may have encountered this error:

ImportError: cannot import name 'six' from 'django.utils'

This happens because django.utils.six (a built-in compatibility module that helped code run on both Python 2 and Python 3) was removed entirely in Django 3.0. Any code that still tries to import six from Django's utilities will fail immediately.

In this guide, you'll learn why this error occurs, how to fix it in your own code, and how to handle it when it comes from third-party packages.

Why Was django.utils.six Removed?

The six library is a Python 2/3 compatibility layer. It provides utilities to write code that works across both Python versions, handling differences in string types, iterators, metaclasses, and more.

Django bundled its own copy of six inside django.utils for years. However, Django 3.0 dropped Python 2 support entirely, so the compatibility layer was no longer needed. The bundled six module was removed as part of this cleanup.

Timeline:

Django VersionPython 2 Supportdjango.utils.six
Django 2.x✅ Supported✅ Available
Django 3.0+❌ Dropped❌ Removed

Reproducing the Error

Any code that imports six from Django's utilities will trigger the error:

from django.utils import six

Output:

ImportError: cannot import name 'six' from 'django.utils'

This can also appear indirectly when importing a third-party package that internally relies on django.utils.six:

Traceback (most recent call last):
File "manage.py", line 22, in <module>
main()
...
File "/path/to/some_package/utils.py", line 3, in <module>
from django.utils import six
ImportError: cannot import name 'six' from 'django.utils'

Fix 1: Replace django.utils.six with the Standalone six Package

The six library is available as a standalone PyPI package. If your code still needs Python 2/3 compatibility utilities (or uses six helpers like six.text_type or six.moves), install it independently and update your imports.

Step 1: Install the standalone six package

pip install six

Step 2: Update your import statements

Before (broken on Django 3.0+):

from django.utils import six

if six.PY3:
string_type = str
else:
string_type = unicode

After (works on all Django versions):

import six

if six.PY3:
string_type = str
else:
string_type = unicode
tip

A simple find and replace across your project can handle most cases:

  • Find: from django.utils import six
  • Replace with: import six

And:

  • Find: from django.utils.six
  • Replace with: from six

If your project only targets Python 3 (which it should, since Django 3.0+ requires Python 3), you likely don't need six at all. The compatibility layer exists solely to bridge Python 2 and Python 3 differences.

Replace six utilities with their native Python 3 equivalents:

Before:

from django.utils import six

# Check Python version
if six.PY3:
text = str("hello")
else:
text = unicode("hello")

# String type check
if isinstance(value, six.string_types):
print("It's a string")

# Iterate over dictionary items
for key, val in six.iteritems(my_dict):
print(key, val)

After (pure Python 3: no six needed):

# No version check needed: it's always Python 3
text = "hello"

# str is the only string type in Python 3
if isinstance(value, str):
print("It's a string")

# dict.items() is already efficient in Python 3
for key, val in my_dict.items():
print(key, val)

Common six Utilities and Their Python 3 Replacements

six UsagePython 3 Equivalent
six.PY3Always True: remove the check
six.text_typestr
six.binary_typebytes
six.string_types(str,)
six.integer_types(int,)
six.iteritems(d)d.items()
six.itervalues(d)d.values()
six.iterkeys(d)d.keys()
six.moves.rangerange
six.moves.urlliburllib
six.ensure_str(s)s (if already str) or s.decode()
six.with_metaclass(Meta, Base)class MyClass(Base, metaclass=Meta):

Fix 3: Update Third-Party Packages

Often, the error doesn't come from your own code but from an outdated third-party package that still imports django.utils.six internally.

Step 1: Identify the package causing the error

Read the full traceback carefully. Look for the file path that triggers the import:

File "/path/to/venv/lib/python3.11/site-packages/some_old_package/utils.py", line 3, in <module>
from django.utils import six
ImportError: cannot import name 'six' from 'django.utils'

In this example, some_old_package is the culprit.

Step 2: Upgrade the package

pip install --upgrade some_old_package

Most actively maintained packages have already released Django 3.0+ compatible versions.

Step 3: Check compatibility

If the latest version of the package still uses django.utils.six, the package may be abandoned. In that case:

  • Search for a maintained fork on PyPI or GitHub.
  • Find an alternative package that provides the same functionality.
  • Patch it yourself by forking the repository and replacing from django.utils import six with import six.
warning

Do not downgrade Django to fix this error. Django 2.x no longer receives security updates. Keeping your Django version current is critical for security.

Step 4: Audit all your dependencies

To proactively find all packages that might use django.utils.six, search your installed packages:

# Search all installed packages for the problematic import
grep -r "django.utils.six" $(python -c "import site; print(site.getsitepackages()[0])")

Or on Windows (PowerShell):

Select-String -Path "$(python -c 'import site; print(site.getsitepackages()[0])')\*\*.py" -Pattern "django.utils.six" -Recurse

Upgrade any packages that appear in the results.

Full Migration Example

Here's a complete before-and-after example showing a Django view that used six and how to modernize it:

Before (Django 2.x style):

from django.utils import six
from django.http import JsonResponse


def process_input(request):
user_input = request.GET.get("value", "")

if isinstance(user_input, six.text_type):
result = user_input.upper()
elif isinstance(user_input, six.binary_type):
result = user_input.decode("utf-8").upper()
else:
result = str(user_input).upper()

return JsonResponse({"result": result})

After (Django 3.0+ / Python 3):

from django.http import JsonResponse


def process_input(request):
user_input = request.GET.get("value", "")

# In Django 3.0+ with Python 3, request.GET values are always str
result = str(user_input).upper()

return JsonResponse({"result": result})

Output (both versions, given ?value=hello):

{"result": "HELLO"}

Prevention: Keep Dependencies Up to Date

To avoid running into this error in the future, adopt these practices:

  • Pin your dependencies in requirements.txt with compatible version ranges:
Django>=4.2,<5.0
six>=1.16.0 # Only if genuinely needed
  • Run pip list --outdated regularly to check for available updates.
  • Test upgrades in a virtual environment before applying them to your project:
python -m venv test_env
source test_env/bin/activate
pip install -r requirements.txt
python manage.py test

Conclusion

The "ImportError: cannot import name 'six' from 'django.utils'" error occurs because Django 3.0 removed the bundled six compatibility module after dropping Python 2 support. The fix depends on where the import originates:

  • Your own code: Replace from django.utils import six with import six (after installing the standalone package), or better yet, remove six entirely and use native Python 3 equivalents.
  • Third-party packages: Upgrade the package to a version that supports Django 3.0+. If no compatible version exists, find an alternative or fork and patch the package.

For any modern Django project, the cleanest solution is to eliminate six altogether. Since Django 3.0+ requires Python 3, the compatibility layer serves no purpose and removing it makes your code simpler and easier to maintain.