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 Version | Python 2 Support | django.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 sixOutput:
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 sixStep 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 = unicodeAfter (works on all Django versions):
import six
if six.PY3:
string_type = str
else:
string_type = unicodeFix 2: Remove six Entirely (Recommended for Modern Projects)
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
if six.PY3:
text = str("hello")
else:
text = unicode("hello")
if isinstance(value, six.string_types):
print("It's a string")
for key, val in six.iteritems(my_dict):
print(key, val)After (pure Python 3: no six needed):
text = "hello"
if isinstance(value, str):
print("It's a string")
for key, val in my_dict.items():
print(key, val)Common six Utilities and Their Python 3 Replacements
six Usage |
Python 3 Equivalent |
|---|---|
six.PY3 |
Always True: remove the check |
six.text_type |
str |
six.binary_type |
bytes |
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.range |
range |
six.moves.urllib |
urllib |
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_packageMost 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 sixwithimport six.
Step 4: Audit all your dependencies
To proactively find all packages that might use django.utils.six, search your installed packages:
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" -RecurseUpgrade 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", "")
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.txtwith compatible version ranges:
Django>=4.2,<5.0
six>=1.16.0 # Only if genuinely needed- Run
pip list --outdatedregularly 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 testConclusion
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 sixwithimport six(after installing the standalone package), or better yet, removesixentirely 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.