Now that the server is setup and Nginx is handling inbound requests and proxying them to gunicorn/Django it is high time to setup the first git repository and start configuring your Django environment.
Git
I have been using SVN for years and possess a passing familiarity with CVS but I decided to give Git a shot for this particular project. As I mentioned earlier, all the cool kids are using it and more often than not, I find myself browsing through OSS repositories on there all the time.
It is fairly straightforward to get going. Once I setup a paid account (the $7/mth plan), I followed the instructions on how to create the SSH key, setup Git on the server and create my first repository. Once this was done, I committed the root of the Django project folder (with README) into the repository.
Now onto configuring Django.
django-admin.py
I noticed fairly early on that the django-admin.py command was not working correctly. I did some searching around and found the following guide which had a helpful suggestion about adding the DJANGO_SETTINGS_MODULE environment variable to the activate script for virtualenv.
I ran the following commands in the project folder (outside of the virtualenv, replace myproject with your project name) to add this environment variable:
ln -s `pwd` ../lib/python2.6/site-packages/`basename \`pwd\``
export DJANGO_SETTINGS_MODULE=myproject.settings
echo "!!" >> ../bin/activate
Database
As I said in my first post, I am going to try and use MongoDB as the backend database for Django using django-nonrel, djangotoolbox and mongodb-engine.
Using this helpful tutorial as a guide,
Memcached
Using the helpful information provided in this post, I have added the following to the Django settings.py file:
CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
And in the middleware classes section (at the top and bottom):
'django.middleware.cache.UpdateCacheMiddleware',
...
'django.middleware.cache.FetchFromCacheMiddleware',
South
Update: It looks like South does not work with either MongoDB or django-nonrel and may not be required anyway. As soon as I add it to the INSTALLED_APPS section Django will not start.
South improves on the shipped Django schema migration capabilities. Again, with MongoDB, I’m not sure how this particular component will work.
According to the installation guide, you just need to add ‘south’ to the INSTALLED_APPS section (at the very bottom).
django-debug-toolbar
Once I installed the 0.9.0-dev release, everything went fine. There is an issue with 0.8.5 wherein in will display an error on pages that are not defined in the urls.py file.
The django-debug-toolbar is an excellent tool for Django developers. It will display helpful information to a specified address (in the browser) that will help in debugging issues during development.
You need to add the following to the middleware section in your settings.py file:
'debug_toolbar.middleware.DebugToolbarMiddleware',
Just make sure that the memcached FetchFromCacheMiddleware class is left at the bottom of the list.
Then specify an INTERNAL_IPS directive that includes the IP addresses for all of the machines that you are using for development.
Finally, add ‘debug_toolbar’ to the INSTALLED_APPS section.
django-social-auth
The Django-SocialAuth plugin enables authentication via third party providers such as Facebook, Google, Twitter etc.
‘social_auth’ needs to be added to the INSTALLED_APPS section in settings.py.
AUTHENTICATION_BACKENDS need to be specified. I added all of the examples in the install documentation:
AUTHENTICATION_BACKENDS = (
'social_auth.backends.twitter.TwitterBackend',
'social_auth.backends.facebook.FacebookBackend',
'social_auth.backends.google.GoogleOAuthBackend',
'social_auth.backends.google.GoogleOAuth2Backend',
'social_auth.backends.google.GoogleBackend',
'social_auth.backends.yahoo.YahooBackend',
'social_auth.backends.contrib.linkedin.LinkedinBackend',
#'social_auth.backends.contrib.LiveJournalBackend',
'social_auth.backends.contrib.orkut.OrkutBackend',
'social_auth.backends.contrib.FoursquareBackend',
'social_auth.backends.OpenIDBackend',
'django.contrib.auth.backends.ModelBackend',
)
Watch out for issues in the documentation. I have to leave the LiveJournalBackend line commented out and remove the orkut reference in the FoursquareBackend line.
Again, using the documentation, I have added the following to the settings.py file as well (with the keys specified):
TWITTER_CONSUMER_KEY = ''
TWITTER_CONSUMER_SECRET = ''
FACEBOOK_APP_ID = ''
FACEBOOK_API_SECRET = ''
LINKEDIN_CONSUMER_KEY = ''
LINKEDIN_CONSUMER_SECRET = ''
ORKUT_CONSUMER_KEY = ''
ORKUT_CONSUMER_SECRET = ''
GOOGLE_CONSUMER_KEY = ''
GOOGLE_CONSUMER_SECRET = ''
GOOGLE_OAUTH2_CLIENT_KEY = ''
GOOGLE_OAUTH2_CLIENT_SECRET = ''
FOURSQUARE_CONSUMER_KEY = ''
FOURSQUARE_CONSUMER_SECRET = ''
LOGIN_URL = '/login-form/'
LOGIN_REDIRECT_URL = '/logged-in/'
LOGIN_ERROR_URL = '/login-error/'
SOCIAL_AUTH_ERROR_KEY = 'social_errors'
SOCIAL_AUTH_COMPLETE_URL_NAME = 'complete'
SOCIAL_AUTH_ASSOCIATE_URL_NAME = 'associate_complete'
SOCIAL_AUTH_DEFAULT_USERNAME = 'new_social_auth_user'
SOCIAL_AUTH_EXTRA_DATA = False
SOCIAL_AUTH_EXPIRATION = 'expires'
Finally, add the following to the urls.py file:
url(r'', include('social_auth.urls')),
The Social_Auth section in the Django admin will fail with the following message when trying to access Associations, Nonces or User social auths.
Exception Type: TemplateSyntaxError
Exception Value:
Caught DatabaseError while rendering: This query is not supported by the database.
Exception Location: build/bdist.linux-i686/egg/djangotoolbox/db/basecompiler.py in check_query, line 272
Not surprising as it is most likely attempting a join behind the scenes. I have forked the social_auth repository on github for fun to see if I can figure it out. For now, I will leave it enabled to see if authentication works anyway.
django-easy-maps
django-easy-maps makes deploying Google Maps much easier in Django projects. As I plan on using them in this web application, I thought I would check out this plugin.
According to the documentation you need to add ‘easy_maps’ to INSTALLED_APPS and then specify your Google key in EASY_MAPS_GOOGLE_KEY in settings.py.
Admin, views.py and urls.py
Since we are using MongoDB, the SITE_ID in settings.py must be an ObjectID string or else the following error is issued:
AutoField (default primary key) values must be strings representing an ObjectId on MongoDB (got u’1′ instead). Please make sure your SITE_ID contains a valid ObjectId string.
I added the following to the INSTALLED_APPS sections:
'django_mongodb_engine',
'djangotoolbox',
Adding djangotoolbox here is not just recommended it is required if you plan on creating or editing users in the Django admin panel. The following command is supposed to return the ObjectID value:
python manage.py tellsiteid
Unfortunately, this did not work for me so I went over into the MongoDB engine and found the ObjectID with the following (dbname is the one specified in settings.py):
/usr/bin/mongo dbname
db.django_site.find()
This will return on ObjectID which you can add to your settings.py file by commenting out the existing value and replace it with:
SITE_ID = u'OBJECTIDVALUE'
Now, you will need to enable the admin module, create your first views.py file and make a few more changes to the urls.py file to have a working site.
To enable the admin module uncomment the following in settings.py:
'django.contrib.admin',
And uncomment the following in urls.py:
from django.contrib import admin
admin.autodiscover()
...
url(r'^admin/', include(admin.site.urls)),
Now, create a views.py file in the root of your project folder and add the following:
from django import forms
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.http import Http404
from django.core.mail import send_mail
from django.contrib import auth
from django.contrib.auth.decorators import login_required
from django.template import RequestContext
from django.core.urlresolvers import reverse
def home(request):
return render_to_response('home.html', locals(), context_instance=RequestContext(request))
render_to_response is a Django shortcut which will render a defined template (home.html) and pass in context variables (locals() and RequestContext(request)). This is why I included the import statements above.
Now, where does it find home.html? You need to specify a templates folder in settings.py in the TEMPLATE_DIRS section. Make sure you use a fully qualified path (without trailing space). In this case, I created a templates folder under the project path (in the same folder as urls.py, views.py and settings.py). Create a home.html file in that folder.
That’s it! Reload gunicorn using the following command:
kill -HUP `cat /tmp/gunicorn.pid`
You should now see a functioning page!
Commit and syncdb
Finally, commit the recent changes to the Git repository and synchronize the Django database.
git add -A
git commit -m 'Enter comment here'
In order to run the syncdb command, you need to be in the virtualenv for the path to be setup correctly. So:
source bin/activate
python manage.py syncdb