Update tutorial part 1 to discuss migrations properly
This commit is contained in:
parent
67b51b9895
commit
0b3c8fc851
|
@ -267,8 +267,9 @@ that, run the following command:
|
|||
|
||||
The :djadmin:`migrate` command looks at the :setting:`INSTALLED_APPS` setting
|
||||
and creates any necessary database tables according to the database settings
|
||||
in your :file:`mysite/settings.py` file. You'll see a message for each
|
||||
database table it creates, and you'll get a prompt asking you if you'd like to
|
||||
in your :file:`mysite/settings.py` file and the database migrations shipped
|
||||
with the app (we'll cover those later). You'll see a message for each
|
||||
migration it applies, and you'll get a prompt asking you if you'd like to
|
||||
create a superuser account for the authentication system. Go ahead and do
|
||||
that.
|
||||
|
||||
|
@ -282,7 +283,7 @@ display the tables Django created.
|
|||
case, but not everybody needs them. If you don't need any or all of them,
|
||||
feel free to comment-out or delete the appropriate line(s) from
|
||||
:setting:`INSTALLED_APPS` before running :djadmin:`migrate`. The
|
||||
:djadmin:`migrate` command will only create tables for apps in
|
||||
:djadmin:`migrate` command will only run migrations for apps in
|
||||
:setting:`INSTALLED_APPS`.
|
||||
|
||||
.. _creating-models:
|
||||
|
@ -322,6 +323,8 @@ That'll create a directory :file:`polls`, which is laid out like this::
|
|||
polls/
|
||||
__init__.py
|
||||
admin.py
|
||||
migrations/
|
||||
__init__.py
|
||||
models.py
|
||||
tests.py
|
||||
views.py
|
||||
|
@ -338,6 +341,11 @@ The first step in writing a database Web app in Django is to define your models
|
|||
the :ref:`DRY Principle <dry>`. The goal is to define your data model in one
|
||||
place and automatically derive things from it.
|
||||
|
||||
This includes the migrations - unlike in Ruby On Rails, for example, migrations
|
||||
are entirely derived from your models file, and are essentially just a
|
||||
history that Django can roll through to update your database schema to
|
||||
match your current models.
|
||||
|
||||
In our simple poll app, we'll create two models: ``Question`` and ``Choice``.
|
||||
A ``Question`` has a question and a publication date. A ``Choice`` has two fields:
|
||||
the text of the choice and a vote tally. Each ``Choice`` is associated with a
|
||||
|
@ -437,31 +445,69 @@ Now Django knows to include the ``polls`` app. Let's run another command:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python manage.py sql polls
|
||||
$ python manage.py makemigrations polls
|
||||
|
||||
You should see something similar to the following (the ``CREATE TABLE`` SQL
|
||||
statements for the polls app):
|
||||
You should see something similar to the following:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Migrations for 'polls':
|
||||
0001_initial.py:
|
||||
- Create model Question
|
||||
- Create model Choice
|
||||
|
||||
By running ``makemigrations``, you're telling Django that you've made
|
||||
some changes to your models (in this case, you've made new ones) and that
|
||||
you'd like the changes to be stored as a *migration*.
|
||||
|
||||
Migrations are how Django stores changes to your models (and thus your
|
||||
database schema) - they're just files on disk. You can read the migration
|
||||
for your new model if you like; it's the file
|
||||
``polls/migrations/0001_initial.py``. Don't worry, you're not expected to read
|
||||
them every time Django makes one, but they're designed to be human-editable
|
||||
in case you want to manually tweak how Django changes things.
|
||||
|
||||
There's a command that will run the migrations for you and manage your database
|
||||
schema automatically - that's called :djadmin:`migrate`, and we'll come to it in a
|
||||
moment - but first, let's see what SQL that migration would run. The
|
||||
:djadmin:`sqlmigrate` command takes migration names and returns their SQL:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python manage.py sqlmigrate polls 0001
|
||||
|
||||
|
||||
You should see something similar to the following (we've reformatted it for
|
||||
readability):
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
BEGIN;
|
||||
CREATE TABLE "polls_question" (
|
||||
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
CREATE TABLE polls_question (
|
||||
"id" serial NOT NULL PRIMARY KEY,
|
||||
"question_text" varchar(200) NOT NULL,
|
||||
"pub_date" datetime NOT NULL
|
||||
"pub_date" timestamp with time zone NOT NULL
|
||||
);
|
||||
CREATE TABLE "polls_choice" (
|
||||
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"question_id" integer NOT NULL REFERENCES "polls_poll" ("id"),
|
||||
|
||||
CREATE TABLE polls_choice (
|
||||
"id" serial NOT NULL PRIMARY KEY,
|
||||
"question_id" integer NOT NULL,
|
||||
"choice_text" varchar(200) NOT NULL,
|
||||
"votes" integer NOT NULL
|
||||
);
|
||||
COMMIT;
|
||||
|
||||
CREATE INDEX polls_choice_7aa0f6ee ON "polls_choice" ("question_id");
|
||||
|
||||
ALTER TABLE "polls_choice"
|
||||
ADD CONSTRAINT polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id
|
||||
FOREIGN KEY ("question_id")
|
||||
REFERENCES "polls_question" ("id")
|
||||
DEFERRABLE INITIALLY DEFERRED;
|
||||
|
||||
|
||||
Note the following:
|
||||
|
||||
* The exact output will vary depending on the database you are using. The
|
||||
example above is generated for SQLite.
|
||||
example above is generated for PostgreSQL.
|
||||
|
||||
* Table names are automatically generated by combining the name of the app
|
||||
(``polls``) and the lowercase name of the model -- ``question`` and
|
||||
|
@ -472,8 +518,9 @@ Note the following:
|
|||
* By convention, Django appends ``"_id"`` to the foreign key field name.
|
||||
(Yes, you can override this, as well.)
|
||||
|
||||
* The foreign key relationship is made explicit by a ``REFERENCES``
|
||||
statement.
|
||||
* The foreign key relationship is made explicit by a ``FOREIGN KEY``
|
||||
constraint. Don't worry about the ``DEFERRABLE`` parts; that's just telling
|
||||
PostgreSQL to not enforce the foreign key until the end of the transaction.
|
||||
|
||||
* It's tailored to the database you're using, so database-specific field types
|
||||
such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or ``integer
|
||||
|
@ -481,34 +528,15 @@ Note the following:
|
|||
goes for quoting of field names -- e.g., using double quotes or single
|
||||
quotes.
|
||||
|
||||
* The :djadmin:`sql` command doesn't actually run the SQL in your database -
|
||||
it just prints it to the screen so that you can see what SQL Django thinks
|
||||
is required. If you wanted to, you could copy and paste this SQL into your
|
||||
database prompt. However, as we will see shortly, Django provides an
|
||||
easier way of committing the SQL to the database.
|
||||
* The :djadmin:`sqlmigrate` command doesn't actually run the migration on your
|
||||
database - it just prints it to the screen so that you can see what SQL
|
||||
Django thinks is required. It's useful for checking what Django is going to
|
||||
do or if you have database administrators who require SQL scripts for
|
||||
changes.
|
||||
|
||||
If you're interested, also run the following commands:
|
||||
|
||||
* :djadmin:`python manage.py validate <validate>` -- Checks for any errors
|
||||
in the construction of your models.
|
||||
|
||||
* :djadmin:`python manage.py sqlcustom polls <sqlcustom>` -- Outputs any
|
||||
:ref:`custom SQL statements <initial-sql>` (such as table modifications or
|
||||
constraints) that are defined for the application.
|
||||
|
||||
* :djadmin:`python manage.py sqlclear polls <sqlclear>` -- Outputs the
|
||||
necessary ``DROP TABLE`` statements for this app, according to which
|
||||
tables already exist in your database (if any).
|
||||
|
||||
* :djadmin:`python manage.py sqlindexes polls <sqlindexes>` -- Outputs the
|
||||
``CREATE INDEX`` statements for this app.
|
||||
|
||||
* :djadmin:`python manage.py sqlall polls <sqlall>` -- A combination of all
|
||||
the SQL from the :djadmin:`sql`, :djadmin:`sqlcustom`, and
|
||||
:djadmin:`sqlindexes` commands.
|
||||
|
||||
Looking at the output of those commands can help you understand what's actually
|
||||
happening under the hood.
|
||||
If you're interested, you can also run
|
||||
:djadmin:`python manage.py validate <validate>`; this checks for any errors in
|
||||
your models without making migrations or touching the database.
|
||||
|
||||
Now, run :djadmin:`migrate` again to create those model tables in your database:
|
||||
|
||||
|
@ -516,12 +544,38 @@ Now, run :djadmin:`migrate` again to create those model tables in your database:
|
|||
|
||||
$ python manage.py migrate
|
||||
|
||||
The :djadmin:`migrate` command runs the SQL from :djadmin:`sqlall` on your
|
||||
database for all apps in :setting:`INSTALLED_APPS` that don't already exist in
|
||||
your database. This creates all the tables, initial data and indexes for any
|
||||
apps you've added to your project since the last time you ran :djadmin:`migrate`.
|
||||
:djadmin:`migrate` can be called as often as you like, and it will only ever
|
||||
create the tables that don't exist.
|
||||
Operations to perform:
|
||||
Synchronize unmigrated apps: sessions, admin, messages, auth, staticfiles, contenttypes
|
||||
Apply all migrations: polls
|
||||
Synchronizing apps without migrations:
|
||||
Creating tables...
|
||||
Installing custom SQL...
|
||||
Installing indexes...
|
||||
Installed 0 object(s) from 0 fixture(s)
|
||||
Running migrations:
|
||||
Applying polls.0001_initial... OK
|
||||
|
||||
|
||||
The :djadmin:`migrate` command takes all the migrations that haven't been
|
||||
applied (Django tracks which ones are applied using a special table in your
|
||||
database called ``django_migrations``) and runs them against your database -
|
||||
essentially, synchronising the changes you made to your models with the schema
|
||||
in the database.
|
||||
|
||||
Migrations are very powerful and let you change your models over time, as you
|
||||
develop your project, without the need to delete your database or tables and
|
||||
make new ones - it specialises in upgrading your database live, without
|
||||
losing data. We'll cover them in more depth in a later part of the tutorial,
|
||||
but for now, remember the three-step guide to making model changes:
|
||||
|
||||
* Change your models (in models.py)
|
||||
* Run ``python manage.py makemigrations`` to create migrations for those changes
|
||||
* Run ``python manage.py migrate`` to apply those changes to the database.
|
||||
|
||||
The reason there's separate commands to make and apply migrations is because
|
||||
you'll commit migrations to your version control system and ship them with
|
||||
your app; they not only make your development easier, they're also useable by
|
||||
other developers and in production.
|
||||
|
||||
Read the :doc:`django-admin.py documentation </ref/django-admin>` for full
|
||||
information on what the ``manage.py`` utility can do.
|
||||
|
|
Loading…
Reference in New Issue