When Gunicorn fails, but runserver works

Sometimes I am cheating on PHP with Python (PHP knows and it doesn’t appear to mind). I was developing a Django project and it worked perfectly with manage.py runserver but when run through Gunicorn it was failing with an ImportError.

This really got me worked up – as a programmer, I hate when I don’t understand why something would work in one environment but fail in another.

The problem was circular import in Python!

I had two apps in this project: news and comments. News had the following model:

import comments.models

class Article(Model):
    ...
    ...
    def get_root_comment(self):
    try:
        root = comments.models.Comment.objects.get(article=self, level=0)
    except:
        root = comments.models.Comment.objects.create(article=self, body=self.title)
    return root

Comments had something like this:

from news.models import Article

class Comment(MPTTModel, TimeStampedModel):
    ....
    article = models.ForeignKey(Article, related_name='comments')

This worked perfectly well with Django’s built in server, but failed when I tried to run it through Gunicorn. For some reason, this kind of circular import just doesn’t work with it! I am still trying to figure out why, but meanwhile, the fix was to reference ForeigKey with a string. Now I don’t have the offending import in comments/models.py and I reference the foreign key like this:

class Comment(MPTTModel, TimeStampedModel):
    ...
    article = models.ForeignKey("news.Article", related_name='comments')