Upgrade Django from 1.1 to 1.5.1. This highlights some of the issues that one may encounter when updating Django. It's not possible to cover every case, but this should provide a good general starting point.
Django now supports multiple databases and changes are needed to how the database connections are defined.
- Changed in Django 1.2
- Change Required by Django 1.4
- Source:
- https://docs.djangoproject.com/en/dev/releases/1.2/#specifying-databases Need to change the format for the databases variable
Django refactored the Cross Site Request Forgery detection code. As a result, one must explicitly add a template tag to every Django form in the site and change the csrf middleware. This can be quite time-consuming if the application as a lot of forms. Third party modules will also need to be checked for compatibility.
- Source: https://docs.djangoproject.com/en/dev/releases/1.2/#csrf-protection
- Detail: https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#upgrading-notes
- Changed in Django 1.2
- Change Required by Django 1.2
Solution:
-
The {% csrf_token %} template tag is needed for all Django forms in the application.
-
Need to remove the old the CSRF middleware class/s and add the new one: django.middleware.csrf.CsrfViewMiddleware
MIDDLEWARE_CLASSES = (
'django.contrib.csrf.middleware.CsrfMiddleware, 'django.contrib.csrf.middleware.CsrfViewMiddleware' 'django.contrib.csrf.middleware.CsrfResponseMiddleware''django.middleware.csrf.CsrfViewMiddleware', )
A Javascript snippet must be added to the site to protect Javascript POST data from cross site scripting attacks.
- Changed in Django 1.2.5
- Change Required by Django 1.2.5
- Source: https://docs.djangoproject.com/en/dev/releases/1.2.5/#csrf-exception-for-ajax-requests
Solution:
- The Javascript snippet should be added to support POSTs through js
- Need to add to the global site template
- Source: https://docs.djangoproject.com/en/dev/releases/1.1/#features-deprecated-in-1-1
- Changed in Django 1.1
- Change Required by Django 1.3
Solution:
- In the urls.py which includes the admin urls, make the following change:
From: (r'^admin/(.*)', admin.site.root), To: (r'^admin/', include(admin.site.urls)),
- Any code using admin.site.root needs to be refactored
Django implemented tighter integration with the Python logging module. The change requires that one add skeleton configuration in the settings.py. In Django 1.5, the absence of this skeleton configuration generates errors when DEBUG is False.
- Changed in Django 1.3
- Unsure when required by
Manifestation: File "/usr/local/lib/python2.7/logging/config.py", line 503, in configure raise ValueError("dictionary doesn't specify a version")
- Source: https://docs.djangoproject.com/en/dev/releases/1.3/#logging
- Logging variables to be added to support emailing exceptions
Django replaced function-based generic views with class-based views. As of Django 1.5, they have deprecated the old function based views. If these function-based generic views are used, some coding work will need to be done.
Source: https://docs.djangoproject.com/en/dev/releases/1.3/#function-based-generic-views
- Changed in Django 1.3
- Change Required by Django 1.5
- Generic function-based views have been deprecated. Need to convert to class-based
- Search for the following views and re-implement.
django.views.generic.create_update django.views.generic.date_based django.views.generic.list_detail django.views.generic.simple
Effective in Django 1.5, syntax for the { % url %} template tag has changed. Now, all url names used in a url template tag must be enclosed in quotes. This is to allow variables to be passed in as url names.
Source: https://docs.djangoproject.com/en/dev/releases/1.3/#changes-to-url-and-ssi
- Changed in Django 1.3
- Change Required by Django 1.5
Solutions: One needs to search for instances of the url tags and place quotes around them. This can be quite time consuming depending on how many urls there are.
Example: From: {% url my_favorite_view arg1 arg2 %} To: {% url 'my_favorite_view' arg1 arg2 %}
This is an optional update. Django now has a built-in static media (non-changing images, css, js) process. Using the collect static command, static files are copied to the specified web-server-accessible directory.
Source: https://docs.djangoproject.com/en/dev/releases/1.3/#extended-static-files-handling
- Changed in Django 1.3
- Use is not required, but strongly recommended
Solution: There are a lot of steps needed to configure, and the Django docs cover the subject in detail. However, some of the basic steps include the following:
- May need to make changes to nginx/apache to support new location
- Set the STATICFILES_DIRS, STATICFILES_FINDERS, STATIC_ROOT, and STATIC_URL variables in settings.py
- Need to add " django.contrib.staticfiles" to INSTALLED_APPS in settings.py
- Add static media context processor in settings.py
TEMPLATE_CONTEXT_PROCESSORS = ( "django.core.context_processors.media", + 'django.core.context_processors.static',
- Go through the application's codebase and replace the URL prefix for all the static media with {{ STATIC_URL }}. Note: this requires that each view is passed the RequestContext (more on this later)
- As an alternative to the {{ STATIC_URL }}, one may use the staticfiles template tag. This does not have the RequestContext dependency.
For Example:
{{ STATIC_URL }} or {% staticfiles %} {% static "relative/path/to/static/file.css" %}
As of Django 1.2, the template loaders settings has changed to load class-based template loaders. This will break in Django 1.4 if not changed.
Source: https://docs.djangoproject.com/en/dev/releases/1.4/#django-core-template-loaders
Change Detail: https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
- Changed in Django 1.2
- Change Required by Django 1.4
- Need to change the TEMPLATE_LOADERS variable to new setting in settings.py
Solution: Replace as follows. See Change Detail link.
Replace : django.core.template_loaders.* With : django.template.loader.*
Example: TEMPLATE_LOADERS = (- 'django.template.loaders.filesystem.load_template_source',- 'django.template.loaders.app_directories.load_template_source',+ 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader'
As of 1.2, the context processor for auth has been moved out of Django core into contrib.
- Changed in Django 1.2
- Change Required by Django 1.4
Manifestation: This results in error messages such as: "Module "django.core.context_processors" does not define a "auth" callable request processor"
Solution:
- For the TEMPLATE_CONTEXT_PROCESSORS variable in settings.py, change the Auth context processor as follows:
TEMPLATE_CONTEXT_PROCESSORS = (- "django.core.context_processors.auth",+ "django.contrib.auth.context_processors.auth",
When enabling the new CSRF protection, Django required that the messaging middleware be installed. Once the messaging middleware was installed, the CSRF middleware stopped complaining. However, there are a few other steps to fully enable the messaging framework.
Change Detail: https://docs.djangoproject.com/en/1.5/ref/contrib/messages/
- Changed in Django 1.2
Solution:
- Add the new middleware to MIDDLEWARE_CLASSES 'django.contrib.messages.middleware.MessageMiddleware',
- Add the new middleware to TEMPLATE_CONTEXT_PROCESSORS 'django.contrib.messages.context_processors.messages'.
- Add the module to INSTALLED_APPS 'django.contrib.messages'
In order to make Django more Pythonic, the location of manage.py was changed in Django 1.4.
- Changed in Django 1.4;
- Change Required by Django 1.6
Source: https://docs.djangoproject.com/en/dev/releases/1.4/#updated-default-project-layout-and-manage-py
Interesting discussion about the reasoning behind this change: https://groups.google.com/forum/?fromgroups=#!topic/django-developers/RLcKN_9zKYs
Solution: need to support new project layout, utilizing new manage.py and moving location. See above link.
- The location of manage.py should be moved one directory above its previous location.
- The contents of manage.py have changed. See the associated link.
Django feeds has been implemented by a slight module name change.
Source: https://github.com/kgrodzicki/django-news-system/issues/1
- Changed in Django 1.2
- Change Required by Django 1.4
Manifestation: from django.contrib.syndication.feeds import Feed "ImportError: No module named feeds"
Solution: check for old Feed import. Replace as follows.
Replace: from django.contrib.syndication.feeds import Feed With: from django.contrib.syndication.views import Feed
Manifestation: Could not import django.contrib.syndication.views.feed
Solution: check to make sure that the old imports are not being used. If the view string "django.contrib.syndication.views.feed" string is provided in urls.py it needs to replaced with the following django.contrib.syndication.views.Feed
Example: urlpatterns += patterns('',- (r'^feeds/(?P.*)/$', 'django.contrib.syndication.views.feed', ….+ (r'^feeds/(?P.*)/$','django.contrib.syndication.views.Feed', ….
The previously undocumented Django FilterSpecs module has been removed and replaced with a new ListFilter module. FilterSpecs were used to customize the list filter options in the admin interface. The new ListFilter module is an improved approach and is similar to the original FilterSpecs. Code that uses FilterSpecs will need to be re-coded.
Source: https://docs.djangoproject.com/en/dev/releases/1.4/#list-filters-in-admin-interface
- Changed in Django 1.4
- Change Required by Django 1.5
Manifestation: from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec Exception Type: ImportError at / Exception Value: No module named filterspecs
Solution: this requires a coding effort and is different for each application. See the link above for the API documentation.
Django 1.4 introduced timezone support. Django now contains a new now() method which is timezone aware.
Source: https://docs.djangoproject.com/en/dev/topics/i18n/timezones/#time-zones-migration-guide
- Changed in Django 1.4
- Use is not required, but strongly recommended
Solution: check for old import . Replace calls to the following module as follows.
Replace: from datetime.datetime.now() With: from django.utils.timezone.now()
Source: https://docs.djangoproject.com/en/dev/releases/1.3/#python-compatibility
- Changed in Django 1.2
- Change Required by Django 1.2
- As a consequence, the virtualenv needs to be re-built or re-initialized.
- Compiled binaries will need to rebuild
Source: https://docs.djangoproject.com/en/dev/releases/1.4/#python-compatibility
- Changed in Django 1.4
- Change Required by Django 1.4
- As a consequence, the virtualenv needs to be re-built or re-initialized.
- Compiled binaries will need to rebuild.
Django 1.5+ requires at least Python 2.6
Source: https://docs.djangoproject.com/en/dev/releases/1.5/#python-compatibility
- Changed in Django 1.5
- Change Required by Django 1.5
- As a consequence, the virtualenv needs to be re-built or re-initialized.
- Compiled binaries will need to rebuild
As of Django 1.5, simplejson is no longer included.
- Change Required by Django 1.5
Source: https://docs.djangoproject.com/en/dev/releases/1.5/#system-version-of-simplejson-no-longer-used
Manifestation: calls to django.utils.simplejson will raise an ImportError
Solution:
- As Django requires Python 2.6 and 2.6 contains the json library, the any imports using simplejson can simply be replaced. Make sure simplejson imports are not in the codebase. Use "import json" instead.
Separate packages are utilized for localflavor and must be installed and the import paths changed.
Source: https://docs.djangoproject.com/en/dev/releases/1.5/#django-contrib-localflavor
Change Detail: https://docs.djangoproject.com/en/dev/topics/localflavor/#how-to-migrate
- Changed in Django 1.5
- Change Required by Django 1.6
Solution:
- Check for forms and modules using django.contrib.localflavor fields and install external app according to the links above
Due to a security issue, Django no longer checks to see if urls exist for urls entered into a URLField. The verify_exists keyword argument has been deprecated.
Source: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/
- Changed in Django 1.2.6 and 1.3.1
- Change Required by Django 1.5
- verify_exists has been removed from URLField in Django 1.5. -
- Throws an exception if present
Solution:
- Do greps and make code replacement
For Example: From: website = models.URLField(verify_exists=False, blank=True) To: website = models.URLField(blank=True)
As of Django 1.5, the location of a variety of url utility modules are no longer available from django.http. They can be used in django.utils.http. Most notable, impacted methods include, urlquote and urlencode.
- Changed in Django 1.0 or before
- Change Required by Django 1.5
Solution:
- Update the imports as follows
From: from django.http import urlencode To: from django.utils.http import urlencode
Old views that do not pass in a RequestContext to the render_to_response shortcut will experience problems with CSRF {% csrf_token %} protection and using the {{ STATIC_URL }} context variables. These views
Solution:
- These views should be updated to pass in the RequestContext if possible.
- As an alternative, Django 1.3+ shortcuts offer a render() method that may be used in place of render_to_response() and will automatically pass in the request context.
Change detail: https://docs.djangoproject.com/en/1.5/topics/http/shortcuts/#render
For example: From: return render_to_response(template, {}) To: from django.template import RequestContext return render_to_response(template, {}, context_instance=RequestContext(request))
As of 1.5, the template library adminmedia containing admin_media_prefix is no longer available.
- Changed in Django 1.4
- Change Required by Django 1.5
This template tag was located in django.contrib.admin.templatetags.adminmedia
Source: https://docs.djangoproject.com/en/1.5/releases/1.5/#miscellaneous
Change detail: http://stackoverflow.com/questions/13624458/appropriate-way-to-handle-deprecated-adminmedia-templatetag-and-admin-media
Solution:
- This must be removed from template code and possible replaced with STATIC_URL from Django staticfiles. See the Stackoverflow link for a good example.
As of 1.5, django.http.get_host has been changed. Instead of importing this method and passing the request upon calling the method, it is now a method on the request object. New request.get_host() syntax available since Django 1.0 or before
- Change Required by Django 1.5
Solution: [kstateome/django-cas#15 https://github.com/kstateome/django-cas/commit/b92610a615c3b950d5bc3c939d171f8a59b899a5][20]
Make the following change
- host = get_host(request)+ host = request.get_host()
As of Django 1.5, the ALLOWED_HOSTS setting is required in settings.py. This first was introduced in Django 1.4.4 but was set to ["*"] by default. In 1.5, the default value has been removed and needs to be set.
- Changed in Django 1.4.4
- Change Required by Django 1.5
Manifestation: "Server Error (500)" when DEBUG=False
Python 2.5 has moved the md5 module.
- Changed in python 2.5
Manifestation: DeprecationWarning: the md5 module is deprecated; use hashlib instead import md5
Solution: (backwards compatible)
try: from hashlib import md5 except ImportError: import md5
Field.get_db_prep_value(), Field.get_db_prep_lookup(), and Field.get_db_prep_save() function signature changed.
The methods Field.get_db_prep_value(), Field.get_db_prep_lookup(), and Field.get_db_prep_save() in module django.db.models.fields.init.py changed to take additional arguments to support multiple database. If you override this method, you will need to pass in these additional arguments.
- Changed in Django 1.2
- Change Required by Django 1.2
Manifestation: File "/iscape/sites/mysite2/lib/python2.6/site-packages/django/core/handlers/base.py", line 115, in get_response response = callback(request, *callback_args, **callback_kwargs) File "/iscape/sites/mysite2/proj/mysite/mysite/vendors/form_designer/views.py", line 88, in detail result = process_form(request, form_definition) File "/iscape/sites/mysite2/proj/mysite/mysite/vendors/form_designer/views.py", line 58, in process_form form_definition.log(form) File "/iscape/sites/mysite2/proj/mysite/mysite/vendors/form_designer/models.py", line 79, in log FormLog(form_definition=self, data=self.get_form_data(form)).save() File "/iscape/sites/mysite2/lib/python2.6/site-packages/django/db/models/base.py", line 546, in save force_update=force_update, update_fields=update_fields) File "/iscape/sites/mysite2/lib/python2.6/site-packages/django/db/models/base.py", line 650, in save_base result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw) File "/iscape/sites/mysite2/lib/python2.6/site-packages/django/db/models/manager.py", line 215, in _insert return insert_query(self.model, objs, fields, **kwargs) File "/iscape/sites/mysite2/lib/python2.6/site-packages/django/db/models/query.py", line 1661, in insert_query return query.get_compiler(using=using).execute_sql(return_id) File "/iscape/sites/mysite2/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 936, in execute_sql for sql, params in self.as_sql(): File "/iscape/sites/mysite2/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 894, in as_sql for obj in self.query.objs TypeError: get_db_prep_save() got an unexpected keyword argument 'connection'
Example: From: def get_db_prep_value(self, value): To: def get_db_prep_value(self, value, connection, prepared=False): Example: From: def get_db_prep_save(self, value): To: def get_db_prep_save(self, value, connection): Example: From: def get_db_prep_lookup(self, lookup_type, value): To: def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):
- Change Required by Django 1.6
Unhandled exception in thread started by Traceback (most recent call last): File "/mysite/local/lib/python2.7/site-packages/django/utils/autoreload.py", line 93, in wrapper fn(*args, **kwargs) File "/mysite/local/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 98, in inner_run self.validate(display_num_errors=True) File "/mysite/local/lib/python2.7/site-packages/django/core/management/base.py", line 310, in validate num_errors = get_validation_errors(s, app) File "/mysite/local/lib/python2.7/site-packages/django/core/management/validation.py", line 34, in get_validation_errors for (app_name, error) in get_app_errors().items(): File "/mysite/local/lib/python2.7/site-packages/django/db/models/loading.py", line 196, in get_app_errors self._populate() File "/mysite/local/lib/python2.7/site-packages/django/db/models/loading.py", line 78, in _populate self.load_app(app_name) File "/mysite/local/lib/python2.7/site-packages/django/db/models/loading.py", line 99, in load_app models = import_module('%s.models' % app_name) File "/mysite/local/lib/python2.7/site-packages/django/utils/importlib.py", line 40, in import_module __import__(name) File "/mysite/proj/myproject/myproject/models.py", line 4, in from django.utils.text import truncate_words ImportError: cannot import name truncate_words
Solution:
try: from django.utils.text import truncate_words except ImportError: from django.template.defaultfilters import truncatewords as truncate_words
Traceback (most recent call last): File "/usr/lib/python2.7/wsgiref/handlers.py", line 85, in run self.result = application(self.environ, self.start_response) File "/mysite/local/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 206, in __call__ response = self.get_response(request) File "/mysite/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 194, in get_response response = self.handle_uncaught_exception(request, resolver, sys.exc_info()) File "/mysite/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 232, in handle_uncaught_exception if resolver.urlconf_module is None: File "/mysite/local/lib/python2.7/site-packages/django/core/urlresolvers.py", line 360, in urlconf_module self._urlconf_module = import_module(self.urlconf_name) File "/mysite/local/lib/python2.7/site-packages/django/utils/importlib.py", line 40, in import_module __import__(name) File "/mysite/proj/myproj/myproj/urls/__init__.py", line 9, in admin.autodiscover() File "/mysite/local/lib/python2.7/site-packages/django/contrib/admin/__init__.py", line 29, in autodiscover import_module('%s.admin' % app) File "/mysite/local/lib/python2.7/site-packages/django/utils/importlib.py", line 40, in import_module __import__(name) File "/mysite/proj/myproj/myproj/libs/grappelli/admin.py", line 8, in from django.utils.functional import update_wrapper ImportError: cannot import name update_wrapper
Solution:
FROM from django.utils.functional import update_wrapper TO from functools import update_wrapper
16: Source: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/
[20]: kstateome/django-cas#15 https://github.com/kstateome/django-cas/commit/b92610a615c3b950d5bc3c939d171f8a59b899a5