Преглед на файлове

Update tutorial part 1 to discuss migrations properly

Andrew Godwin преди 11 години
родител
ревизия
0b3c8fc851
променени са 1 файла, в които са добавени 104 реда и са изтрити 50 реда
  1. 104 50
      docs/intro/tutorial01.txt

+ 104 - 50
docs/intro/tutorial01.txt

@@ -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:
+
+.. 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 (the ``CREATE TABLE`` SQL
-statements for the polls app):
+
+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.
-
-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.
+* 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.
 
-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.