Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django site using mod_wsgi on AWS cannot create FK form field because related model has not been loaded yet

I'm working on a Django site, using the Django 1.4 official release. My site has a few apps. One of the apps has a model named Campaign with FKs to models in the other apps. As suggested in the Django reference (https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey), I chose to define the FK fields using a string instead of the related model classes themselves since I expect to have circular references in the next version or so, and this approach avoids circular import issues.

When I deployed the site on AWS (Amazon Web Services) using the BitNami djangostack 1.4 (Apache, mod_wsgi, MySQL), my deployed site worked correctly for the most part. On pages displaying forms for the Campaign model, Django raised an exception when trying to create a form field relying on a foreign key field of the Campaign model, complaining the related model was not loaded. The funny/scary thing is that when I set settings.DEBUG to True (definitely not something we'll want once the site goes live), the issue no longer occurs!

The site worked perfectly when I tested it on my local Django development server, and it also worked perfectly using the same BitNami djangostack deployed on my Windows workstation.

Here's the relevant Apache error output I see on the AWS console.

[error] ERROR :: Internal Server Error: /campaigns/
[error] Traceback (most recent call last):
[error]   File "/opt/bitnami/apps/django/lib/python2.6/site-packages/django/core/handlers/base.py", line 101, in get_response
[error]     request.path_info)
    ... (django/wsgi blah blah)
[error]   File "/opt/bitnami/apps/django/django_projects/Project/campaign/views.py", line 5, in <module>
[error]     from forms import CampaignForm
[error]   File "/opt/bitnami/apps/django/django_projects/Project/campaign/forms.py", line 12, in <module>
[error]     class CampaignForm(forms.ModelForm):
[error]   File "/opt/bitnami/apps/django/lib/python2.6/site-packages/django/forms/models.py", line 206, in __new__
[error]     opts.exclude, opts.widgets, formfield_callback)
[error]   File "/opt/bitnami/apps/django/lib/python2.6/site-packages/django/forms/models.py", line 160, in fields_for_model
[error]     formfield = f.formfield(**kwargs)
[error]   File "/opt/bitnami/apps/django/lib/python2.6/site-packages/django/db/models/fields/related.py", line 1002, in formfield
[error]     (self.name, self.rel.to))
[error] ValueError: Cannot create form field for 'reward' yet, because its related model 'reward.Reward' has not been loaded yet

So, here's a quick recap:

  1. My site works on my local Django development server, regardless of settings.DEBUG value
  2. With the BitNami stack on my local Windows machine, it works, regardless of settings.DEBUG value
  3. With the BitNami stack on AWS (Ubuntu), it works with DEBUG = True but not with DEBUG = False

I understand what the error means, but I don't understand why it's occurring, i.e. why the dependent model is not loaded. Has anyone ever encountered a similar issue, or has advice that could help me fix it?

Note: I tried to Google the error message but all I found was the Django source code where that error was raised. I also tried searching for more general queries like mod_wsgi django related model, but I couldn't find anything that seemed relevant to my problem.

like image 273
mbargiel Avatar asked Feb 21 '23 23:02

mbargiel


1 Answers

Alright, I found a solution to my problem on a blog post by Graham Dumpleton (http://blog.dscpl.com.au/2010/03/improved-wsgi-script-for-use-with.html).

In short, the Django development server validates the models (which resolves string-based relations) when starting, and that operation probably wasn't done when using mod_wsgi under the BitNami djangostack on Ubuntu with DEBUG = False. Very specific conditions, I know - but G. Dumpleton's 'fixed' mod_wsgi code solved the issue for me.

This is what my wsgi.py looks like now:

#wsgi.py

#make sure the folder containing the apps and the site is at the front of sys.path
#maybe we could just define WSGIPythonPath in django.conf file...?
project_root = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 
if project_root not in sys.path:
    sys.path.insert(0, project_root)

#set the DJANGO_SETTINGS_MODULE environment variable (doesn't work without this, despite what G. Dumpleton's blog post said)
site_name = os.path.basename(os.path.dirname(__file__))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "%s.settings" % site_name)

#new code - fixes inter-app model dependencies
from my_site import settings
import django.core.management
django.core.management.setup_environ(settings)  # mimic manage.py
utility = django.core.management.ManagementUtility()
command = utility.fetch_command('runserver')
command.validate()  # validate the models - *THIS* is what was missing

#setup WSGI application object
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
like image 76
mbargiel Avatar answered Apr 06 '23 06:04

mbargiel