I’m sure everyone has one of these lying around, but here’s mine in case you are as lazy a programmer as I usually am. The only thing Django-specific about it is that it reads your database configuration directly out of your settings file.
If you run this via cron it will automatically create its backup directory and a zipped SQL dump with the name of the current day of the week. If one already exists, it simply overwrites it. This means you’ll have a week’s worth of daily rolling backups. If you need more granularity, add a timestamp to the datestamp. If you need more persistent backups, switch to a full date scheme.
The latest version of this can always been found here.
#!/usr/bin/env python import sys import os.path import os import logging from datetime import datetime from settings import DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD logging.basicConfig(level=logging.WARN) BACKUP_DIR = "%s/backups" % os.path.dirname(__file__) MYSQL_CMD = 'mysqldump' ZIP_CMD = 'zip' def _setup(): if not os.path.exists(BACKUP_DIR): logging.debug("Created backup directory %s" % BACKUP_DIR) os.mkdir(BACKUP_DIR) else: logging.debug("Using backup directory %s" % BACKUP_DIR) def _backup_name(): now = datetime.now() day_name = now.strftime("%A") file_name = "%s.sql" % day_name.lower() logging.debug("Setting backup name for day name %s as %s" % (day_name, file_name)) return file_name def _run_backup(file_name): cmd = "%(mysqldump)s -u %(user)s --password=%(password)s %(database)s > %(log_dir)s/%(file)s" % { 'mysqldump' : MYSQL_CMD, 'user' : DATABASE_USER, 'password' : DATABASE_PASSWORD, 'database' : DATABASE_NAME, 'log_dir' : BACKUP_DIR, 'file': file_name} logging.debug("Backing up with command %s " % cmd) return os.system(cmd) def _zip_backup(file_name): backup = "%s/%s" % (BACKUP_DIR, file_name) zipfile_name = "%s.zip" % (backup) if os.path.exists(zipfile_name): logging.debug("Removing previous zip archive %s" % zipfile_name) os.remove(zipfile_name) zip_cmds = {'zip' : ZIP_CMD, 'zipfile' : zipfile_name, 'file' : backup } # Create the backup logging.debug("Making backup as %s " % zipfile_name) os.system("%(zip)s -q -9 %(zipfile)s %(file)s" % zip_cmds) # Test our archive logging.debug("Testing zip archive") if not os.system("%(zip)s -T -D -q %(zipfile)s" % zip_cmds): # If there was no problem, then delete the unzipped version os.remove(backup) return True else: return False def main(*args): _setup() file_name = _backup_name() _run_backup(file_name) return(_zip_backup(file_name)) if __name__ == '__main__': sys.exit(main(*sys.argv))