How to use a South data migration to avoid accidentally sending emails from example.com.
Consider the following snippet from Django’s docs1 for sending a confirmation email:
from django.contrib.sites.models import Site from django.core.mail import send_mail def register_for_newsletter(request): current_site = Site.objects.get_current() send_mail( 'Thanks for subscribing to %s alerts' % current_site.name, 'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name, 'editor@%s' % current_site.domain, [user.email] )
Here the domain for the email sender is taken from the ‘current site’ instance,
which is controlled by
Django’s ‘Sites’ framework
and accessible by a custom method on the manager of the
By default, a
Site instance is created with domain and display name
’example.com’ and you have to correct these values. This is often done by hand
using the admin suite.
However, as with any manual change, it’s easy to forget and you’ll often find
Django projects sending email from
firstname.lastname@example.org. Highly embarassing.
Automation, of course! We can use a South data migration to set the domain and display name correctly in each environment.
First, ensure that each environment has settings for the domain and site name.
# conf/test.py ... DOMAIN_NAME = 'test.project.client.tangentlabs.co.uk' SITE_NAME = 'project - client (test)' # conf/stage.py ... DOMAIN_NAME = 'stage.project.client.tangentlabs.co.uk' SITE_NAME = 'project - client (stage)'
This snippet assumes you are using a set-up similar to that outlined by
David Cramer, where an
environmental variable specifies an additional settings file to import. You
don’t have to use this method; employing a
settings_local.py file for each
environment works just as well.
Next, create a data migration to set the domain and display name correctly in
each environment. This migration sits most naturally in the
django.contrib.sites app, but since that’s in Django’s core, it’s not an
option. You could use an existing app within your project to house the migration
or perhaps create a simple ‘core’ or ‘data’ app to house data migrations that
alter 3rd party apps.
Since we’re not using the actual app where the
Site model is defined, we must
--freeze option to ensure the
Site model is available to the
python manage.py datamigration <appname> create_domains --freeze=sites
Finally implement the
from south.v2 import DataMigration from django.conf import settings class Migration(DataMigration): def forwards(self, orm): Site = orm['sites.Site'] site = Site.objects.get(id=settings.SITE_ID) site.domain = settings.DOMAIN_NAME site.name = settings.SITE_NAME site.save()
Then your next deployment to each environment will perform the update.