Updating Django 1.8 on Python 2.7 to Django 1.11 on Python 3.6

I recently updated a few Django apps from Python 2.7 to Python 3.6 and while going from Django 1.8 to Django 1.11. This is mainly for my own reference, but others may find it useful.

Move the existing virtualenv (this will break the app):

mv ~/.virtualenvs/wbstats ~/.virtualenvs/wbstats2

Create a new virtualenv:

mkvirtualenv -p /usr/bin/python3 wbstats

At this point it might be a good idea to update the version of Django in requirements.txt. For WbStats it moved from 1.8 to 1.11.

Pip install the requirements.txt:

pip install -f requirements.txt

Edit settings.py and make sure there is a TEMPLATES section, which replaces TEMPLATE_DIRS. In addition, TEMPLATE_CONTEXT_PROCESSORS no longer exists. Basically anything with TEMPLATE_ has been rolled into the TEMPLATES section.

You may need to change some imports, i.e.

from models import *

may become:

from stats.models import *

The URLs will probably choke because strings are no longer allowed. Do not import “patterns”. Urlpatterns now is an array: urlpatterns = [url(…), url(…)]

'stats.views.index'

may need to be changed to:

from stats import views
views.index

After imports are fixed, the next thing will probably be fixing print statements.

Urlparse has been moved.

import urlparse

becomes:

import urllib.parse as urlparse

If you updated Django you’ll probably need to run migrations.

python manage.py migrate

Admin commands will need to be ported:

     option_list = BaseCommand.option_list + (make_option('-d', '--domain', default=None, action='store', type='string', dest='domain', help='The name of a domain to create or update.'),)

Becomes:

     def add_arguments(self, parser):
          parser.add_argument('-d', '--domain', default=None, action='store', dest='domain', help='The name of a domain to create or update.')

The parser arguments are mostly the same, but  references to “type=’int'” should be changed “type=int” without quotes, otherwise you’ll get ValueError: ‘int’ is not callable.

There’s some code in some of the admin commands I’ve written that changes the codec for stdout:

UTF8Writer = codecs.getwriter(‘utf8’)
sys.stdout = UTF8Writer(sys.stdout)

This will NEED to be removed because it causes cryptic TypeError problems saying things must be str and not bytes.

render_to_response needs to change to render because context_instance doesn’t exist.