All articles, tagged with “django”

HTTPS with django and WSGI

Fighting with deployed django app over WSGI with SSL enabled, I’ve found this snippet for middleware and this receipt for wsgi script.

This works almost fine, except sometime views fall into infinitive loop with redirect http->https->http->https. This make me nervous, so to save solution how to make this 2 scripts work together:

#SSl middleware
#ssl.py
#original — http://www.djangosnippets.org/snippets/240/
#use {'SSL':True} for the urls which should be redirected to https
from django.conf import settings
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect, get_host

import django.contrib.auth.decorators
import os

SSL = 'SSL'

def is_secure(request):
    if 'HTTPS' in request.META:
        return request.META['HTTPS'] == 'on'
    return False


class SSLRedirect:
    def process_view(self, request, view_func, view_args, view_kwargs):
        if SSL in view_kwargs:
            secure = view_kwargs[SSL]
            del view_kwargs[SSL]
        else:
            secure = False

        if not secure == request.is_secure():
	    f=open('/tmp/workfile', 'a')

            f.write( "\nrequest.is_secure: "+str(request.is_secure()) )
            f.write( "\nrequest.build_absolute_uri: "+request.build_absolute_uri() )
            f.close()
            if secure and settings.SSL_ENABLED:
                 return self._redirect(request, secure)

    def _redirect(self, request, secure):
        if settings.DEBUG and request.method == 'POST':
            raise RuntimeError(
"""Django can't perform a SSL redirect while maintaining POST data.
Please structure your views so that redirects only occur during GETs.""")

        protocol = secure and "https" or "http"

        newurl = "%s://%s%s" % (protocol,get_host(request),request.get_full_path())


	f=open('/tmp/workfile', 'a')
	f.write( "\nnewurl: "+newurl        )
        f.close()
        os.environ["HTTPS"] = "on"
	os.environ['wsgi.url_scheme'] = 'https'
	return HttpResponsePermanentRedirect(newurl)



#original — http://www.fairviewcomputing.com/blog/2008/10/23/django-wsgi-handler-ssl-proxies/
#some changes to get right environment 
#project.wsgi
import os, sys
sys.path.insert(0, '/project/django')
sys.path.insert(1, '/project')

os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings'
os.environ['PYTHON_EGG_CACHE'] = '/project/pythoneggs'

import logging

from django.conf import settings
import django.core.handlers.wsgi


class WSGIRequest(django.core.handlers.wsgi.WSGIRequest):
    def is_secure(self):
        logger = logging.getLogger('project.wsgi.WSGIRequest.is_secure')
        header = getattr(settings, 
                            'FC_WSGI_PROTOCOL_HEADER',
                            'HTTP_X_FORWARDED_PROTO'
                            )

        https_value = getattr(settings,
                                'FC_WSGI_PROTOCOL_HTTPS_VALUE',
                                'https'
                                ).lower()

        http_value = getattr(settings,
                                'FC_WSGI_PROTOCOL_HTTP_VALUE',
                                'http'
                                ).lower()
        value = self.META.get(header, '').lower()

        if settings.DEBUG:
            logger.debug("""HEADER: '%s' HTTPS value: '%s' HTTP value: '%s' request value: '%s'""" % (header, https_value, http_value, value))
        if value == https_value or os.environ.get('HTTPS','off') in ('on','1'):
            if settings.DEBUG:
                logger.debug("""Request is secure.""")
            return True

        if settings.DEBUG:
            logger.debug("""Request is insecure.""")
        return False

class WSGIHandler(django.core.handlers.wsgi.WSGIHandler):
    request_class = WSGIRequest

_application = WSGIHandler()

def application(environ, start_response):
    environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO']
    if environ.get('HTTPS','off') in ('on','1'):
	environ['wsgi.url_scheme'] = 'https'
    else:
	environ['wsgi.url_scheme'] = 'http'
    if environ['wsgi.url_scheme'] == 'https':
	    environ['HTTPS'] = 'on'

    return _application(environ, start_response)

TDD with Django. Part 2. Twill tests

Testing of the web projects is very hard. We try to cover all application with unit tests and twill tests. And if we have a lot of javascript, we also make selenium tests.

To use twill tests from the nosetests and Django, we’ve created simple helper to create many tests faster. Here is it:

 # -*- coding: utf-8 -*-
 IP = '127.0.0.1'
 PORT = 8088
 SITE = 'http://%s:%s' % (IP, PORT)

 class TwillMock(object):

    def setup(self):
        '''
        — setup twill virtual web server
        '''
        from django.core.servers.basehttp import AdminMediaHandler
        from django.core.handlers.wsgi import WSGIHandler

        app = AdminMediaHandler(WSGIHandler())
        add_wsgi_intercept(IP, PORT, lambda: app)

Making new test class derived from the TwillMock class make creation of nose twill tests much easier.
Look at the example of such test:

class TestLogin(TwillMock):

    def test_start_page(self):
        """
        Test start_page view
        """
        go(SITE)
        code(200)
        check_links()

    def test_login(self):
        go(SITE + '/accounts/login/')
        code(200)
        show()
        formvalue(1, 'username',  'test1')
        formvalue(1, 'password', 'test1')
        submit()
        code(200)

Django projects version policy

Some weeks ago, Django get his own clear release process : http://docs.djangoproject.com/en/dev/internals/release-process/

I have proposed rules for our team to create Django-projects:

  • We develop using current stable version (1.0, 1.1 or 1.1.4)
  • If security Django release appears (e.g. 1.0.3) every project immediately moves to this release
  • If our project should be released after new “big” Django release or just before (1-2 weeks) , separate branch should be created and project should be tested vs Django beta. After final release, this separate branch becomes master.
  • For special cases, e.g. project is long-tem and cover Django 1.0 and 2.0, which will be incompatible, policy should be discussed additionally.

Now we are using 1.0.X trunk, http://code.djangoproject.com/svn/django/branches/releases/1.0.X/

Do you agree? What policy do you use?

Django release!

Many thanks to Django team and congratulations to all django-users!

Release notes, Porting guide

TDD with Django. Part 1

Starting my first big Django-project (Building.ua), I hadn’t know anything about TDD except the fact it is. Project was done but it is very buggy and hard for future develop.
After very productive work with Andrey Khavryuchenko , I’ve learnt his model of tests and now try to add some points to it to make it cover near 100% of the Django application.

All tests in Django-TDD I’d like to divide into parts:
— Unit tests
— Integration and modification tests
— Twill html tests
— Selenium tests
— Other specific tests (e.g. test RTF or PDF output)

Andrey use nosetest in all python projects. And this model is better for me as standard Djando UnitTest derived testrunner. The biggest issue of such model is that you can use one test templates for all your python projects. Second, we use nosetest with coverage plugin which give us very useful metric to know how code is tested.

Unit tests for every new Django model looks like:
— create/edit/delete object of the model
— call unicode() and get_absolute_url() methods

Extensions of the model results appearing new tests in the testscase for this model.

All unit and integration django tests we create as the subclasses of the DbMock class. As a result every test has it’s own clean database and we don’t care about it.

For testing simple html functions and interactions we use Twill. Twill give the possibility to run by the pages, find and fill the forms and check results. Of course, you could use Selenium for this too, but in this case Twill is more cheaper solution.

To run Twill (and Selenium), we create virtual Django WSGI server and connect to it from the tests.


For testing javascript iterations, we use Selenium-RC, which have good python interface. The biggest problem for Selenium tests — is to run this tests on the buildbot servers. The one solution I see — is to setup server with X and set Selenium to run Firefox on this server.

I am planning to write some code in next articles to show our examples for running nose/twill/selenium tests for Django application.