Arrow of time
Arrow of time

Installing Django on Windows

Though it is obviously a blasphemy, sometimes it is actually necessary to run Django on Windows - mostly due to a ...

Though it is obviously a blasphemy, sometimes it is actually necessary to run Django on Windows - mostly due to a client having based its infrastructure around the Windows ecosystem. The "blasphemy" part comes from Django being a really nice framework which evolved on and for a Unix-like system, and it relies heavily on features like WSGI, FastCGI, and command-line tooling which are foreign to the Windows environment. Luckily, the compatibility is improving, by features being added both to the Windows side and to the Python+Django side - features which would otherwise be a kludge but which solve crucial compatibility problems.

This short tutorial will demonstrate the the basic set-up of a Django project on Windows. It will cover the installation of Python, Django, and related tools, and running the Django project both standalone and as a FastCGI server. The latter part is especially important since the IIS officially supports FastCGI as of lately (on IIS 7+, simply install the CGI feature). The tutorial will cover Python 2.7 and Django 1.7 as I use those versions for my projects.

The tutorial is intended for people which have working understanding of Windows and are familiar with the IIS server.

Pro tip: If you are going to deploy multiple Django (or even plain Python) projects, or if you are a developer, you should look at virtualenv.

Installing Python on Windows

First, download Python. Both 32-bit and 64-bit MSI installers are provided, and you should choose one accordingly. It is especially important that you install Python 2.7.9 or a later version, since they come with PIP, the Python library / package / software manager which is used to install everything else.

The installer process is very straightforward and simple. It will offer to install Python in the C:\Python27 directory, which you should accept as it makes life easier afterwards. Try not to give in to the Windows habit of installing stuff in directories with spaces in their names.

The basic directory after installation will contain around 8 subdirectories, some miscellaneous files and two executables named Python.exe and PythonW.exe. The former is the default command-line interpreter and Python shell, while the latter is only the interpreter, which will not use (or spawn) a console window if invoked (and because of that is suitable for running GUI Python applications).

Next, Python should be added to the system's PATH environment variable. This is done in Advanced System Settings (or System Properties), in the Advanced tab, by clicking on the Environment Variables button. There are two directories to be added: C:\Python27 and C:\Python27\Scripts. These should be appended to the PATH list, separated by semicolons (;). The ending of your PATH variable should look like ;C:\Python27;C:\Python27\Scripts.

Pro tip: You may also want to install GOW, a light-weight collection of Unix command-line utilities similar to Cygwin. It will provide you with tools such as ls, but also more interesting ones such as make, wget, curl, ssh, scp, gzip and tar.

The basics of PIP

PIP is the tool which installs and maintains Python libraries (of which Django is only one example; there are thousands of useful Python libraries). It is invoked by running the pip command on the command prompt, and has several sub-commands, among which the two most useful ones are install and freeze.

Running pip install <package_name> will download and install the package and all of its dependencies (which may be nested and fairly complex). Running pip install --upgrade <package_name> will likewise upgrade an existing package to its most recent version. PIP supports a special syntax for installing precise versions of a package instead of the "most recent one". It is done by appending an operator and a version number to the package name, e.g. "Jinja2==2.7.3" or "six>=1.8". The first one will install a precise version of a package, and the second one will install any version equal to or larger than the given version number.

Running pip freeze will simply show the list of currently installed packages, in a format which is directly usable to pip install.

Note that some Python / PIP packages come with a library written in C, which must be compiled for the package to work. Unless you set up your system to have a working C compiler which is also compatible with the Python executables, you will not be able to install those. Django is a pure Python library so it does not require a C compiler to install.

Installing Django

Django can be installed using PIP with a command such as pip install django. The process may pull in some additional dependencies if they are not already present on your system. Otherwise, it will simply install only Django, with an output similar to the following:

Downloading/unpacking django
Installing collected packages: django
Successfully installed django
Cleaning up...

You can check if both Python and Django are working by starting a new Windows Command Prompt, running the python command, and writing the import django command in the Python prompt:

Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>>

If everything goes ok, no output should be visible.

PIP is also the way project dependencies (additional libraries) are installed, should the project have them.

Installing a Django project

A Django "project" consists of one or more "apps". A project's top-level directory usually contains one special project subdirectory which contains settings and some general project-level information, one subdirectory per app, and a command-line script called "manage.py". An example directory listing is:

C:\Devel\djangoproject\src>dir
 Volume in drive C is OS
 Volume Serial Number is 6A3D-C1B8

 Directory of C:\Devel\djangoproject\src

22/12/2014  04:25    <DIR>          .
22/12/2014  04:25    <DIR>          ..
22/12/2014  04:19    <DIR>          project
22/12/2014  04:58    <DIR>          djangoapp
16/12/2014  03:30    <DIR>          templates
16/12/2014  00:50               250 manage.py
                           1 File(s)            250 bytes
                           5 Dir(s)  23,552,929,792 bytes free

Django projects can be simply distributed by archiving the entire project directory and decompressing it on another machine. In the example above, the project contains the "project" subdirectory, the application directory named "djangoapp", and an auxiliarry "templates" subdirectory.

The manage.py script is the "swiss army knife" of Django applications - it does everything from creating new apps, to database migrations, to running a test (embedded) HTTP server or a FastCGI server.

Running a test HTTP server

If the project and its apps are functional, you should be able to start the default Django development-only HTTP server by running the command manage.py runserver, which will result in an output similar to the following:

C:\Devel\djangoproject\src>manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
December 23, 2014 - 01:19:02
Django version 1.7.1, using settings 'project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

As you can see from the messages, it will start a server on localhost, port 8000. You can access it immediately with your web browser.

Configuring and running a FastCGI server

A more interesting option is enabling a FastCGI server. With FastCGI, you can use IIS, Apache or any other web server to serve the application in a production setting. For this to work you need to download the fcgi.py file (also available at its original location and put it into the management/commands subdirectory of the Django app's (not the project's!) subdirectory. Both the "management" and the "commands" subdirectory must have an empty file named __init__.py (which make those directories Python modules).

The fcgi.py described previously is a very simple and minimalistic WSGI to FastCGI adaptor which does not support listening on a TCP socket or a pipe, and does all its processing by using stdin and stdout. As such it is not usable with modern web servers such as nginx, but will work with IIS.

Configuring IIS to run a FastCGI application

If the FastCGI module is loaded in IIS (or simple the CGI module in IIS 7+), the IIS management console will have the "FastCGI Settings" icon available. Django is a framework which has its own URL routing, so django apps must be installed as a "handler" in IIS for specific paths. To install a Django app on the IIS's Default Web Site, select it in the management console, and open the Handler mappings configuration feature. In it, click on the Add Module Mapping... action, and enter the following information:

  • Request path: set it to '*' to handle all requests with internal Django routing
  • Module: set it to 'FastCgiModule' to use the IIS's FastCGI module
  • Executable: here both the python.exe path and its command line arguments need to be set, using the pipe character (|) as a separator. An example value for this setting is: C:\Python27\python.exe|C:\Devel\simplebom\src\manage.py fcgi --pythonpath C:\Devel\simplebom\src --settings project.settings. Note that you need to specify the fcgi command for the manage.py script, and manually set the Python interpreter's search path for the project, as well as the Pythonic module name for the project's setting module.
  • Name: set it to whatever you like

Your configuration dialog should look something like this:

A Django app handler configuration for the IIS

Next, click the Request restrictions button and edit the Mapping tab. You need to turn off the "Invoke handler only if the request is mapped to..." checkbox, or otherwise IIS will have problems mapping what it thinks are subdirectories in the URL request:

Turning off request restrictions for mappings

After clicking OK on the handler information dialog, IIS will ask you to confirm the creation of a matching FastCGI application entry, and you must allow it to make one. This entry will be visible in the FastCGI Settings feature, accessible at the root screen of the IIS Management Console. The default entry created by IIS itself is good enough to work with, but there are some optional settings available which can be very convenient:

  • Max instances: This particular way of running FastCGI applications is single-process, single-threaded, meaning a separate Python interpreter process will be started for each simultaneous request. This setting limits the number of simultaneous Django app instances.
  • Monitor changes to file: By default, once started, the app processes will be active either until manually shut down, or until they handle Instance MaxRequest requests. By using this setting, IIS will monitor a timestamp of an arbitrary file, and if it changes, it will stop and reload app instances. This is convenient both for developers and for production environments, as it allows apps to be reloaded when changed. The "monitor a file's timestamp for a reload indicator" is a fairly strange concept on Windows, but it's normal in Unix-like environments, and so it was carried here with FastCGI.
Configuring a FastCGI app

Configuring the static resource and media directories

Modern web applications use multiple resource files, such as CSS, JavaScript and others, and Django apps are no exceptions. Django provides for a very convenient feature which allows the developers to integrate the needed resources into the application directory tree, but which can be extracted and copied by Django into a proper, static directory. This is basically a developer-controlled feature, and the locations where Django will store the static files is controlled in the project's settings.py. Well-behaved projects will use a reasonably sane path for this, but it is not standardised.

Apps which handle uploaded files store them in a similarly managed directory which in Django is traditionally named media. To handle the static and media directories, they need to be added to the IIS configuration as virtual directories:

Configuring an IIS virtual directory

The important step here is to reconfigure the Handler Mappings feature for each of the directories and remove the Django App handler, leaving the "StaticFile" handler as the most important one.

Note that the static directory must be readable by the IIS (as well as all other files and directories in the Django project), but the media directory must also be writeable by the IIS. The final site configuration should resemble the following screenshot:

IIS configured with Django :width: 500

A note on databases

SQLite works by default, on Windows as on Unix-like systems. Most of the other open source databases now work on Windows, even PostgreSQL, which I recommend. On existing Windows installations, though, there could be a requirement to deploy Django with the MS SQL Server. This is possible either by using an ODBC bridge driver or by using a native MS SQL driver. In theory, both work but I haven't tested them. At least the database connection parameters (in the project's settings.py file) need to be changed to switch to a new database. Data migration needs to be done manually.

Note that if using the SQLite database, both the database file and the directory where it is located need to be writeable by the IIS.

Troubleshooting

The described configuration is tested and proven to work, but if something goes wrong, here are the steps for basic troubleshooting:

  1. Try starting the FastCGI command line yourself. This is the command configured in the FastCGI Settings and which must match the one configured in Handler Mappings for the site.
  2. Install the Tracing feature for the IIS, then configure it for the Django site in Failed Request Tracing Rules to trace all content (*), the status code "500" and the event severity "Error". The traces will be available as XML files (with attached XSLT) in the IIS's C:\inetpub\logs\FailedReqLogFiles directory (or a similar one, depending on your configuration). You then need to enable tracing for the particular web site (or a virtual directory) in the Configure->Failed request tracing... action.

comments powered by Disqus