Manual Django
Manual Django
When adding a field to a table/model in a production setting, the trick is to take advantage of the fact that
Django doesnt care if a table contains columns that arent defined in the model. The strategy is to add the
column in the database, and then update the Django model to include the new field.
However, theres a bit of a chicken-and-egg problem here, because in order to know how the new database
column should be expressed in SQL, you need to look at the output of Djangos manage.py sqlall command,
which requires that the field exist in the model. (Note that youre not required to create your column with
exactly the same SQL that Django would, but its a good idea to do so, just to be sure everythings in sync.)
The solution to the chicken-and-egg problem is to use a development environment instead of making the
changes on a production server. (You are using a testing/development environment, right?) Here are the
detailed steps to take.
First, take these steps in the development environment (i.e., not on the production server):
1. Add the field to your model.
2. Run manage.py sqlall [yourapp] to see the new CREATE TABLE statement for the model. Note the column
3.
4.
importing the model and selecting from the table (e.g., MyModel.objects.all()[:5]). If you updated the
database correctly, the statement should work without errors.
Then on the production server perform these steps:
1. Start your databases interactive shell.
2. Execute the ALTER TABLE statement you used in step 3 of the development environment steps.
3.
Add the field to your model. If youre using source-code revision control and you checked in your change in
development environment step 1, now is the time to update the code (e.g., svn update, with Subversion) on
the production server.
4. Restart the Web server for the code changes to take effect.
For example, lets walk through what wed do if we added a num_pages field to the Book model from Chapter
5. First, wed alter the model in our development environment to look like this:
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models.IntegerField(blank=True, null=True)
def __unicode__(self):
return self.title
(Note: Read the section Making Fields Optional in Chapter 6, plus the sidebar Adding NOT NULL Columns
below for important details on why we included blank=True and null=True.)
Then wed run the command manage.py sqlall books to see the CREATE TABLE statement. Depending on
your database backend, it would look something like this:
BEGIN;
ALTER TABLE books_book ADD COLUMN num_pages integer;
UPDATE books_book SET num_pages=0;
ALTER TABLE books_book ALTER COLUMN num_pages SET NOT NULL;
COMMIT;
If you go down this path, remember that you should leave off blank=True and null=True in your model
(obviously).
After the ALTER TABLE statement, wed verify that the change worked properly by starting the Python shell
and running this code:
Removing Fields
Removing a field from a model is a lot easier than adding one. To remove a field, just follow these steps:
1. Remove the field from your model and restart the Web server.
2. Remove the column from your database, using a command like this:
1.
Because many-to-many fields are different than normal fields, the removal process is different:
Remove the ManyToManyField from your model and restart the Web server.
2. Remove the many-to-many table from your database, using a command like this: