Index: django/test/testcases.py
===================================================================
--- django/test/testcases.py	(revision 4431)
+++ django/test/testcases.py	(working copy)
@@ -1,5 +1,7 @@
 import re, doctest, unittest
 from django.db import transaction
+from django.core import management
+from django.db.models import get_apps
     
 normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
 
@@ -19,6 +21,7 @@
     def __init__(self, *args, **kwargs):
         doctest.DocTestRunner.__init__(self, *args, **kwargs)
         self.optionflags = doctest.ELLIPSIS
+        management.flush(verbosity=0, interactive=False)
         
     def report_unexpected_exception(self, out, test, example, exc_info):
         doctest.DocTestRunner.report_unexpected_exception(self,out,test,example,exc_info)
@@ -28,3 +31,21 @@
         from django.db import transaction
         transaction.rollback_unless_managed()
 
+class TestCase(unittest.TestCase):    
+    def install_fixtures(self):
+        """If the Test Case class has a 'fixtures' member, clear the database and
+        install the named fixtures at the start of each test.
+        
+        """
+        management.flush(verbosity=0, interactive=False)
+        if hasattr(self, 'fixtures'):
+            management.load_data(self.fixtures, verbosity=0)
+
+    def run(self, result=None):
+        """Wrapper around default run method so that user-defined Test Cases 
+        automatically call install_fixtures without having to include a call to 
+        super().
+        
+        """
+        self.install_fixtures()
+        super(TestCase, self).run(result)
Index: django/test/__init__.py
===================================================================
--- django/test/__init__.py	(revision 4431)
+++ django/test/__init__.py	(working copy)
@@ -0,0 +1,6 @@
+"""
+Django Unit Test and Doctest framework.
+"""
+
+from django.test.client import Client
+from django.test.testcases import TestCase
Index: django/db/backends/ado_mssql/base.py
===================================================================
--- django/db/backends/ado_mssql/base.py	(revision 4431)
+++ django/db/backends/ado_mssql/base.py	(working copy)
@@ -134,6 +134,19 @@
 def get_pk_default_value():
     return "DEFAULT"
 
+def get_sql_flush(sql_styler, full_table_list):
+    """Return a list of SQL statements required to remove all data from
+    all tables in the database (without actually removing the tables
+    themselves) and put the database in an empty 'initial' state
+    """
+    # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
+    # TODO - SQL not actually tested against ADO MSSQL yet!
+    # TODO - autoincrement indices reset required? See other get_sql_flush() implementations
+    sql_list = ['%s %s;' % \
+                (sql_styler.SQL_KEYWORD('TRUNCATE'),
+                 sql_styler.SQL_FIELD(quote_name(table))
+                 )  for table in full_table_list]
+
 OPERATOR_MAPPING = {
     'exact': '= %s',
     'iexact': 'LIKE %s',
Index: django/db/backends/postgresql/base.py
===================================================================
--- django/db/backends/postgresql/base.py	(revision 4431)
+++ django/db/backends/postgresql/base.py	(working copy)
@@ -145,6 +145,52 @@
 def get_pk_default_value():
     return "DEFAULT"
 
+def get_sql_flush(style, tables, sequences):
+    """Return a list of SQL statements required to remove all data from
+    all tables in the database (without actually removing the tables
+    themselves) and put the database in an empty 'initial' state
+    
+    """
+    # Postgres can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
+    # truncate tables referenced by a foreign key in any other table. The result is a
+    # single SQL TRUNCATE statement.
+    if tables:
+        sql = ['%s %s;' % \
+            (style.SQL_KEYWORD('TRUNCATE'),
+             style.SQL_FIELD(', '.join(quote_name(table) for table in tables))
+        )]
+    
+        # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
+        # to reset sequence indices
+        for sequence_info in sequences:
+            table_name = sequence_info['table']
+            column_name = sequence_info['column']
+            if column_name and len(column_name)>0:
+                # sequence name in this case will be <table>_<column>_seq
+                sql.append("%s %s %s %s %s %s;" % \
+                    (style.SQL_KEYWORD('ALTER'),
+                    style.SQL_KEYWORD('SEQUENCE'),
+                    style.SQL_FIELD('%s_%s_seq' % (table_name, column_name)),
+                    style.SQL_KEYWORD('RESTART'),
+                    style.SQL_KEYWORD('WITH'),
+                    style.SQL_FIELD('1')
+                    )
+                )
+            else:
+                # sequence name in this case will be <table>_id_seq
+                sql.append("%s %s %s %s %s %s;" % \
+                    (style.SQL_KEYWORD('ALTER'),
+                     style.SQL_KEYWORD('SEQUENCE'),
+                     style.SQL_FIELD('%s_id_seq' % table_name),
+                     style.SQL_KEYWORD('RESTART'),
+                     style.SQL_KEYWORD('WITH'),
+                     style.SQL_FIELD('1')
+                     )
+                )
+        return sql
+    else:
+        return []
+        
 # Register these custom typecasts, because Django expects dates/times to be
 # in Python's native (standard-library) datetime/time format, whereas psycopg
 # use mx.DateTime by default.
Index: django/db/backends/sqlite3/base.py
===================================================================
--- django/db/backends/sqlite3/base.py	(revision 4431)
+++ django/db/backends/sqlite3/base.py	(working copy)
@@ -148,6 +148,24 @@
 def get_pk_default_value():
     return "NULL"
 
+def get_sql_flush(style, tables, sequences):
+    """Return a list of SQL statements required to remove all data from
+    all tables in the database (without actually removing the tables
+    themselves) and put the database in an empty 'initial' state
+    
+    """
+    # NB: The generated SQL below is specific to SQLite
+    # Note: The DELETE FROM... SQL generated below works for SQLite databases
+    # because constraints don't exist
+    sql = ['%s %s %s;' % \
+            (style.SQL_KEYWORD('DELETE'),
+             style.SQL_KEYWORD('FROM'),
+             style.SQL_FIELD(quote_name(table))
+             ) for table in tables]
+    # Note: No requirement for reset of auto-incremented indices (cf. other
+    # get_sql_flush() implementations). Just return SQL at this point
+    return sql
+
 def _sqlite_date_trunc(lookup_type, dt):
     try:
         dt = util.typecast_timestamp(dt)
Index: django/db/backends/mysql/base.py
===================================================================
--- django/db/backends/mysql/base.py	(revision 4431)
+++ django/db/backends/mysql/base.py	(working copy)
@@ -183,6 +183,33 @@
 def get_pk_default_value():
     return "DEFAULT"
 
+def get_sql_flush(style, tables, sequences):
+    """Return a list of SQL statements required to remove all data from
+    all tables in the database (without actually removing the tables
+    themselves) and put the database in an empty 'initial' state
+    
+    """
+    # NB: The generated SQL below is specific to MySQL
+    # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
+    # to clear all tables of all data
+    if tables:
+        sql = ['%s %s;' % \
+                (style.SQL_KEYWORD('TRUNCATE'),
+                 style.SQL_FIELD(quote_name(table))
+                )  for table in tables]
+        # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
+        # to reset sequence indices
+        sql.extend(["%s %s %s %s %s;" % \
+            (style.SQL_KEYWORD('ALTER'),
+             style.SQL_KEYWORD('TABLE'),
+             style.SQL_TABLE(quote_name(sequence['table'])),
+             style.SQL_KEYWORD('AUTO_INCREMENT'),
+             style.SQL_FIELD('= 1'),
+            ) for sequence in sequences])
+        return sql
+    else:
+        return []
+
 OPERATOR_MAPPING = {
     'exact': '= %s',
     'iexact': 'LIKE %s',
Index: django/db/backends/oracle/base.py
===================================================================
--- django/db/backends/oracle/base.py	(revision 4431)
+++ django/db/backends/oracle/base.py	(working copy)
@@ -117,6 +117,20 @@
 def get_pk_default_value():
     return "DEFAULT"
 
+def get_sql_flush(style, tables, sequences):
+    """Return a list of SQL statements required to remove all data from
+    all tables in the database (without actually removing the tables
+    themselves) and put the database in an empty 'initial' state
+    """
+    # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
+    # TODO - SQL not actually tested against Oracle yet!
+    # TODO - autoincrement indices reset required? See other get_sql_flush() implementations
+    sql = ['%s %s;' % \
+            (style.SQL_KEYWORD('TRUNCATE'),
+             style.SQL_FIELD(quote_name(table))
+             )  for table in tables]
+
+
 OPERATOR_MAPPING = {
     'exact': '= %s',
     'iexact': 'LIKE %s',
Index: django/db/backends/postgresql_psycopg2/base.py
===================================================================
--- django/db/backends/postgresql_psycopg2/base.py	(revision 4431)
+++ django/db/backends/postgresql_psycopg2/base.py	(working copy)
@@ -105,6 +105,50 @@
 def get_pk_default_value():
     return "DEFAULT"
 
+def get_sql_flush(style, tables, sequences):
+    """Return a list of SQL statements required to remove all data from
+    all tables in the database (without actually removing the tables
+    themselves) and put the database in an empty 'initial' state
+    """
+    # Postgres can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
+    # truncate tables referenced by a foreign key in any other table. The result is a
+    # single SQL TRUNCATE statement
+    if tables:
+        sql = ['%s %s;' % \
+                (style.SQL_KEYWORD('TRUNCATE'),
+                 style.SQL_FIELD(', '.join(quote_name(table) for table in tables))
+                )]
+        # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
+        # to reset sequence indices
+        for sequence in sequences:
+            table_name = sequence['table']
+            column_name = sequence['column']
+            if column_name and len(column_name) > 0:
+                # sequence name in this case will be <table>_<column>_seq
+                sql.append("%s %s %s %s %s %s;" % \
+                    (style.SQL_KEYWORD('ALTER'),
+                     style.SQL_KEYWORD('SEQUENCE'),
+                     style.SQL_FIELD('%s_%s_seq' % (table_name, column_name)),
+                     style.SQL_KEYWORD('RESTART'),
+                     style.SQL_KEYWORD('WITH'),
+                     style.SQL_FIELD('1')
+                     )
+                )
+            else:
+                # sequence name in this case will be <table>_id_seq
+                sql.append("%s %s %s %s %s %s;" % \
+                    (style.SQL_KEYWORD('ALTER'),
+                     style.SQL_KEYWORD('SEQUENCE'),
+                     style.SQL_FIELD('%s_id_seq' % table_name),
+                     style.SQL_KEYWORD('RESTART'),
+                     style.SQL_KEYWORD('WITH'),
+                     style.SQL_FIELD('1')
+                     )
+                )
+        return sql
+    else:
+        return []
+        
 OPERATOR_MAPPING = {
     'exact': '= %s',
     'iexact': 'ILIKE %s',
Index: django/db/backends/dummy/base.py
===================================================================
--- django/db/backends/dummy/base.py	(revision 4431)
+++ django/db/backends/dummy/base.py	(working copy)
@@ -38,4 +38,6 @@
 get_random_function_sql = complain
 get_fulltext_search_sql = complain
 get_drop_foreignkey_sql = complain
+get_sql_flush = complain
+
 OPERATOR_MAPPING = {}
Index: django/conf/global_settings.py
===================================================================
--- django/conf/global_settings.py	(revision 4431)
+++ django/conf/global_settings.py	(working copy)
@@ -315,3 +315,10 @@
 # The name of the database to use for testing purposes.
 # If None, a name of 'test_' + DATABASE_NAME will be assumed
 TEST_DATABASE_NAME = None
+
+############
+# FIXTURES #
+############
+
+# The list of directories to search for fixtures
+FIXTURE_DIRS = ()
Index: django/core/serializers/base.py
===================================================================
--- django/core/serializers/base.py	(revision 4431)
+++ django/core/serializers/base.py	(working copy)
@@ -141,7 +141,7 @@
 
 class DeserializedObject(object):
     """
-    A deserialzed model.
+    A deserialized model.
 
     Basically a container for holding the pre-saved deserialized data along
     with the many-to-many data saved with the object.
Index: django/core/serializers/__init__.py
===================================================================
--- django/core/serializers/__init__.py	(revision 4431)
+++ django/core/serializers/__init__.py	(working copy)
@@ -40,6 +40,11 @@
     if not _serializers:
         _load_serializers()
     return _serializers[format].Serializer
+
+def get_serializer_formats():
+    if not _serializers:
+        _load_serializers()
+    return _serializers.keys()
     
 def get_deserializer(format):
     if not _serializers:
Index: django/core/management.py
===================================================================
--- django/core/management.py	(revision 4431)
+++ django/core/management.py	(working copy)
@@ -68,6 +68,25 @@
     cursor = connection.cursor()
     return get_introspection_module().get_table_list(cursor)
 
+def _get_sequence_list():
+    "Returns a list of information about all DB sequences for all models in all apps"
+    from django.db import models
+
+    apps = models.get_apps()
+    sequence_list = []
+
+    for app in apps:
+        for model in models.get_models(app):
+            for f in model._meta.fields:
+                if isinstance(f, models.AutoField):
+                    sequence_list.append({'table':model._meta.db_table,'column':f.column,})
+                    break # Only one AutoField is allowed per model, so don't bother continuing.
+
+            for f in model._meta.many_to_many:
+                sequence_list.append({'table':f.m2m_db_table(),'column':None,})
+
+    return sequence_list
+
 # If the foreign key points to an AutoField, a PositiveIntegerField or a
 # PositiveSmallIntegerField, the foreign key should be an IntegerField, not the
 # referred field type. Otherwise, the foreign key should be the same type of
@@ -330,7 +349,15 @@
 get_sql_reset.help_doc = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)."
 get_sql_reset.args = APP_ARGS
 
-def get_sql_initial_data_for_model(model):
+def get_sql_flush():
+    "Returns a list of the SQL statements used to flush the database"
+    from django.db import backend
+    statements = backend.get_sql_flush(style, _get_table_list(), _get_sequence_list())
+    return statements
+get_sql_flush.help_doc = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed."
+get_sql_flush.args = ''
+
+def get_custom_sql_for_model(model):
     from django.db import models
     from django.conf import settings
 
@@ -357,8 +384,8 @@
 
     return output
 
-def get_sql_initial_data(app):
-    "Returns a list of the initial INSERT SQL statements for the given app."
+def get_custom_sql(app):
+    "Returns a list of the custom table modifying SQL statements for the given app."
     from django.db.models import get_models
     output = []
 
@@ -366,12 +393,18 @@
     app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
 
     for model in app_models:
-        output.extend(get_sql_initial_data_for_model(model))
+        output.extend(get_custom_sql_for_model(model))
 
     return output
-get_sql_initial_data.help_doc = "Prints the initial INSERT SQL statements for the given app name(s)."
-get_sql_initial_data.args = APP_ARGS
+get_custom_sql.help_doc = "Prints the custom table modifying SQL statements for the given app name(s)."
+get_custom_sql.args = APP_ARGS
 
+def get_sql_initial_data(apps):
+    "Returns a list of the initial INSERT SQL statements for the given app."
+    return style.ERROR("This action has been renamed. Try './manage.py sqlcustom %s'." % ' '.join(apps and apps or ['app1', 'app2']))
+get_sql_initial_data.help_doc = "RENAMED: see 'sqlcustom'"
+get_sql_initial_data.args = ''
+
 def get_sql_sequence_reset(app):
     "Returns a list of the SQL statements to reset PostgreSQL sequences for the given app."
     from django.db import backend, models
@@ -428,16 +461,26 @@
 
 def get_sql_all(app):
     "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
-    return get_sql_create(app) + get_sql_initial_data(app) + get_sql_indexes(app)
+    return get_sql_create(app) + get_custom_sql(app) + get_sql_indexes(app)
 get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
 get_sql_all.args = APP_ARGS
 
+def _emit_post_sync_signal(created_models, verbosity, interactive):
+    from django.db import models
+    from django.dispatch import dispatcher
+    # Emit the post_sync signal for every application.
+    for app in models.get_apps():
+        app_name = app.__name__.split('.')[-2]
+        if verbosity >= 2:
+            print "Running post-sync handlers for application", app_name
+        dispatcher.send(signal=models.signals.post_syncdb, sender=app,
+            app=app, created_models=created_models,
+            verbosity=verbosity, interactive=interactive)
+
 def syncdb(verbosity=1, interactive=True):
     "Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
     from django.db import connection, transaction, models, get_creation_module
-    from django.db.models import signals
     from django.conf import settings
-    from django.dispatch import dispatcher
 
     disable_termcolors()
 
@@ -499,27 +542,22 @@
 
     # Send the post_syncdb signal, so individual apps can do whatever they need
     # to do at this point.
+    _emit_post_sync_signal(created_models, verbosity, interactive)
+
+    # Install custom SQL for the app (but only if this 
+    # is a model we've just created)
     for app in models.get_apps():
-        app_name = app.__name__.split('.')[-2]
-        if verbosity >= 2:
-            print "Running post-sync handlers for application", app_name
-        dispatcher.send(signal=signals.post_syncdb, sender=app,
-            app=app, created_models=created_models,
-            verbosity=verbosity, interactive=interactive)
-
-        # Install initial data for the app (but only if this is a model we've
-        # just created)
         for model in models.get_models(app):
             if model in created_models:
-                initial_sql = get_sql_initial_data_for_model(model)
-                if initial_sql:
+                custom_sql = get_custom_sql_for_model(model)
+                if custom_sql:
                     if verbosity >= 1:
-                        print "Installing initial data for %s.%s model" % (app_name, model._meta.object_name)
+                        print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
                     try:
-                        for sql in initial_sql:
+                        for sql in custom_sql:
                             cursor.execute(sql)
                     except Exception, e:
-                        sys.stderr.write("Failed to install initial SQL data for %s.%s model: %s" % \
+                        sys.stderr.write("Failed to install custom SQL for %s.%s model: %s" % \
                                             (app_name, model._meta.object_name, e))
                         transaction.rollback_unless_managed()
                     else:
@@ -544,7 +582,10 @@
                     else:
                         transaction.commit_unless_managed()
 
-syncdb.args = ''
+    # Install the 'initialdata' fixture, using format discovery
+    load_data(['initial_data'], verbosity=verbosity)
+syncdb.help_doc = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
+syncdb.args = '[--verbosity] [--interactive]'
 
 def get_admin_index(app):
     "Returns admin-index template snippet (in list form) for the given app."
@@ -597,36 +638,6 @@
     print '\n'.join(output)
 diffsettings.args = ""
 
-def install(app):
-    "Executes the equivalent of 'get_sql_all' in the current database."
-    from django.db import connection, transaction
-
-    app_name = app.__name__.split('.')[-2]
-
-    disable_termcolors()
-
-    # First, try validating the models.
-    _check_for_validation_errors(app)
-
-    sql_list = get_sql_all(app)
-
-    try:
-        cursor = connection.cursor()
-        for sql in sql_list:
-            cursor.execute(sql)
-    except Exception, e:
-        sys.stderr.write(style.ERROR("""Error: %s couldn't be installed. Possible reasons:
-  * The database isn't running or isn't configured correctly.
-  * At least one of the database tables already exists.
-  * The SQL was invalid.
-Hint: Look at the output of 'django-admin.py sqlall %s'. That's the SQL this command wasn't able to run.
-The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
-        transaction.rollback_unless_managed()
-        sys.exit(1)
-    transaction.commit_unless_managed()
-install.help_doc = "Executes ``sqlall`` for the given app(s) in the current database."
-install.args = APP_ARGS
-
 def reset(app, interactive=True):
     "Executes the equivalent of 'get_sql_reset' in the current database."
     from django.db import connection, transaction
@@ -668,8 +679,69 @@
     else:
         print "Reset cancelled."
 reset.help_doc = "Executes ``sqlreset`` for the given app(s) in the current database."
-reset.args = APP_ARGS
+reset.args = '[--interactive]' + APP_ARGS
 
+def flush(verbosity=1, interactive=True):
+    "Returns all tables in the database to the same state they were in immediately after syncdb."
+    from django.conf import settings
+    from django.db import connection, transaction, models
+    from django.dispatch import dispatcher
+    
+    disable_termcolors()
+
+    # First, try validating the models.
+    _check_for_validation_errors()
+
+    # Import the 'management' module within each installed app, to register
+    # dispatcher events.
+    for app_name in settings.INSTALLED_APPS:
+        try:
+            __import__(app_name + '.management', {}, {}, [''])
+        except ImportError:
+            pass
+    
+    sql_list = get_sql_flush()
+
+    if interactive:
+        confirm = raw_input("""
+You have requested a flush of the database.
+This will IRREVERSIBLY DESTROY all data currently in the database,
+and return each table to the state it was in after syncdb.
+Are you sure you want to do this?
+
+Type 'yes' to continue, or 'no' to cancel: """)
+    else:
+        confirm = 'yes'
+
+    if confirm == 'yes':
+        try:
+            cursor = connection.cursor()
+            for sql in sql_list:
+                cursor.execute(sql)
+        except Exception, e:
+            sys.stderr.write(style.ERROR("""Error: Database %s couldn't be flushed. Possible reasons:
+  * The database isn't running or isn't configured correctly.
+  * At least one of the expected database tables doesn't exist.
+  * The SQL was invalid.
+Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
+The full error: """ % settings.DATABASE_NAME + style.ERROR_OUTPUT(str(e)) + '\n'))
+            transaction.rollback_unless_managed()
+            sys.exit(1)
+        transaction.commit_unless_managed()
+
+        # Emit the post sync signal. This allows individual
+        # applications to respond as if the database had been
+        # sync'd from scratch.
+        _emit_post_sync_signal(models.get_models(), verbosity, interactive)
+        
+        # Reinstall the initial_data fixture
+        load_data(['initial_data'], verbosity=verbosity)
+        
+    else:
+        print "Flush cancelled."
+flush.help_doc = "Executes ``sqlflush`` on the current database."
+flush.args = '[--verbosity] [--interactive]'
+
 def _start_helper(app_or_project, name, directory, other_name=''):
     other = {'project': 'app', 'app': 'project'}[app_or_project]
     if not _is_valid_dir_name(name):
@@ -751,7 +823,7 @@
     yield "#     * Make sure each model has one field with primary_key=True"
     yield "# Feel free to rename the models, but don't rename db_table values or field names."
     yield "#"
-    yield "# Also note: You'll have to insert the output of 'django-admin.py sqlinitialdata [appname]'"
+    yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
     yield "# into your database."
     yield ''
     yield 'from django.db import models'
@@ -1239,6 +1311,118 @@
 test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified'
 test.args = '[--verbosity] ' + APP_ARGS
 
+def load_data(fixture_labels, verbosity=1):
+    "Installs the provided fixture file(s) as data in the database."
+    from django.db.models import get_apps
+    from django.core import serializers
+    from django.db import transaction
+    from django.conf import settings
+    import sys
+     
+    # Keep a count of the installed objects and fixtures
+    count = [0,0]
+    
+    humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
+
+    # Start transaction management. All fixtures are installed in a 
+    # single transaction to ensure that all references are resolved.
+    transaction.enter_transaction_management()
+    transaction.managed(True)
+    
+    app_fixtures = [os.path.join(os.path.dirname(app.__file__),'fixtures') for app in get_apps()]
+    for fixture_label in fixture_labels:
+        if verbosity > 0:
+            print "Loading '%s' fixtures..." % fixture_label
+        for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS) + ['']:
+            if verbosity > 1:
+                print "Checking %s for fixtures..." % humanize(fixture_dir)
+            try:
+                fixture_name, format = fixture_label.rsplit('.', 1)
+                formats = [format]
+            except ValueError:
+                fixture_name = fixture_label
+                formats = serializers.get_serializer_formats()
+            
+            label_found = False
+            for format in formats:
+                serializer = serializers.get_serializer(format)
+                if verbosity > 1:
+                    print "Trying %s for %s fixture '%s'..." % \
+                        (humanize(fixture_dir), format, fixture_name)
+                try:
+                    full_path = os.path.join(fixture_dir, '.'.join([fixture_name, format]))
+                    fixture = open(full_path, 'r')
+                    if label_found:
+                        fixture.close()
+                        print style.ERROR("Multiple fixtures named '%s' in %s. Aborting." % 
+                            (fixture_name, humanize(fixture_dir)))
+                        transaction.rollback()
+                        transaction.leave_transaction_management()
+                        return
+                    else:
+                        count[1] += 1
+                        if verbosity > 0:
+                            print "Installing %s fixture '%s' from %s." % \
+                                (format, fixture_name, humanize(fixture_dir))
+                        try:
+                            objects =  serializers.deserialize(format, fixture)
+                            for obj in objects:
+                                count[0] += 1
+                                obj.save()
+                            label_found = True
+                        except Exception, e:
+                            fixture.close()
+                            sys.stderr.write(
+                                style.ERROR("Problem installing fixture '%s': %s\n" % 
+                                     (full_path, str(e))))
+                            transaction.rollback()
+                            transaction.leave_transaction_management()
+                            return
+                        fixture.close()
+                except:
+                    if verbosity > 1:
+                        print "No %s fixture '%s' in %s." % \
+                            (format, fixture_name, humanize(fixture_dir))
+    if count[0] == 0:
+        if verbosity > 0:
+            print "No fixtures found."
+    else:
+        if verbosity > 0:
+            print "Installed %d object(s) from %d fixture(s)" % tuple(count)
+    transaction.commit()
+    transaction.leave_transaction_management()
+        
+load_data.help_doc = 'Installs the named fixture(s) in the database'
+load_data.args = "[--verbosity] fixture, fixture, ..."
+ 
+def dump_data(app_labels, format='json'):
+    "Output the current contents of the database as a fixture of the given format"
+    from django.db.models import get_app, get_apps, get_models
+    from django.core import serializers
+ 
+    if len(app_labels) == 0:
+        app_list = get_apps()
+    else:
+        app_list = [get_app(app_label) for app_label in app_labels]
+ 
+    # Check that the serialization format exists; this is a shortcut to
+    # avoid collating all the objects and _then_ failing.
+    try:
+        serializers.get_serializer(format)
+    except KeyError:
+        sys.stderr.write(style.ERROR("Unknown serialization format: %s\n" % format))        
+    
+    objects = []
+    for app in app_list:
+        for model in get_models(app):
+            objects.extend(model.objects.all())
+    try:
+        print serializers.serialize(format, objects)
+    except Exception, e:
+        sys.stderr.write(style.ERROR("Unable to serialize database: %s\n" % e))
+dump_data.help_doc = 'Output the contents of the database as a fixture of the given format'
+dump_data.args = '[--format]' + APP_ARGS
+
 # Utilities for command-line script
 
 DEFAULT_ACTION_MAPPING = {
@@ -1246,8 +1430,10 @@
     'createcachetable' : createcachetable,
     'dbshell': dbshell,
     'diffsettings': diffsettings,
+    'dumpdata': dump_data,
+    'flush': flush,
     'inspectdb': inspectdb,
-    'install': install,
+    'loaddata': load_data,
     'reset': reset,
     'runfcgi': runfcgi,
     'runserver': runserver,
@@ -1255,6 +1441,8 @@
     'sql': get_sql_create,
     'sqlall': get_sql_all,
     'sqlclear': get_sql_delete,
+    'sqlcustom': get_custom_sql,
+    'sqlflush': get_sql_flush,
     'sqlindexes': get_sql_indexes,
     'sqlinitialdata': get_sql_initial_data,
     'sqlreset': get_sql_reset,
@@ -1271,7 +1459,6 @@
     'createcachetable',
     'dbshell',
     'diffsettings',
-    'install',
     'reset',
     'sqlindexes',
     'syncdb',
@@ -1318,6 +1505,8 @@
         help='Tells Django to NOT prompt the user for input of any kind.')
     parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
         help='Tells Django to NOT use the auto-reloader when running the development server.')
+    parser.add_option('--format', default='json', dest='format',
+        help='Specifies the output serialization format for fixtures')    
     parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
         type='choice', choices=['0', '1', '2'],
         help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
@@ -1351,7 +1540,7 @@
         action_mapping[action](options.plain is True)
     elif action in ('validate', 'diffsettings', 'dbshell'):
         action_mapping[action]()
-    elif action == 'syncdb':
+    elif action in ('flush', 'syncdb'):
         action_mapping[action](int(options.verbosity), options.interactive)
     elif action == 'inspectdb':
         try:
@@ -1365,11 +1554,16 @@
             action_mapping[action](args[1])
         except IndexError:
             parser.print_usage_and_exit()
-    elif action == 'test':
+    elif action in ('test', 'loaddata'):
         try:
             action_mapping[action](args[1:], int(options.verbosity))
         except IndexError:
             parser.print_usage_and_exit()
+    elif action == 'dumpdata':
+        try:
+            action_mapping[action](args[1:], options.format)
+        except IndexError:
+            parser.print_usage_and_exit()
     elif action in ('startapp', 'startproject'):
         try:
             name = args[1]
@@ -1388,6 +1582,10 @@
         action_mapping[action](addr, port, options.use_reloader, options.admin_media_path)
     elif action == 'runfcgi':
         action_mapping[action](args[1:])
+    elif action == 'sqlinitialdata':
+        print action_mapping[action](args[1:])
+    elif action == 'sqlflush':
+        print '\n'.join(action_mapping[action]())
     else:
         from django.db import models
         validate(silent_success=True)

Property changes on: tests/modeltests/fixtures
___________________________________________________________________
Name: svn:ignore
   + *.pyc


Index: tests/modeltests/fixtures/__init__.py
===================================================================

Property changes on: tests/modeltests/fixtures/fixtures
___________________________________________________________________
Name: svn:ignore
   + *.pyc


Index: tests/modeltests/fixtures/fixtures/fixture1.json
===================================================================
--- tests/modeltests/fixtures/fixtures/fixture1.json	(revision 0)
+++ tests/modeltests/fixtures/fixtures/fixture1.json	(revision 0)
@@ -0,0 +1,18 @@
+[
+    {
+        "pk": "2", 
+        "model": "fixtures.article", 
+        "fields": {
+            "headline": "Poker has no place on ESPN", 
+            "pub_date": "2006-06-16 12:00:00"
+        }
+    }, 
+    {
+        "pk": "3", 
+        "model": "fixtures.article", 
+        "fields": {
+            "headline": "Time to reform copyright", 
+            "pub_date": "2006-06-16 13:00:00"
+        }
+    }
+]
\ No newline at end of file
Index: tests/modeltests/fixtures/fixtures/fixture2.json
===================================================================
--- tests/modeltests/fixtures/fixtures/fixture2.json	(revision 0)
+++ tests/modeltests/fixtures/fixtures/fixture2.json	(revision 0)
@@ -0,0 +1,18 @@
+[
+    {
+        "pk": "3", 
+        "model": "fixtures.article", 
+        "fields": {
+            "headline": "Copyright is fine the way it is", 
+            "pub_date": "2006-06-16 14:00:00"
+        }
+    }, 
+    {
+        "pk": "4", 
+        "model": "fixtures.article", 
+        "fields": {
+            "headline": "Django conquers world!", 
+            "pub_date": "2006-06-16 15:00:00"
+        }
+    }
+]
\ No newline at end of file
Index: tests/modeltests/fixtures/fixtures/fixture2.xml
===================================================================
--- tests/modeltests/fixtures/fixtures/fixture2.xml	(revision 0)
+++ tests/modeltests/fixtures/fixtures/fixture2.xml	(revision 0)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+    <object pk="2" model="fixtures.article">
+        <field type="CharField" name="headline">Poker on TV is great!</field>
+        <field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field>
+    </object>
+    <object pk="5" model="fixtures.article">
+        <field type="CharField" name="headline">XML identified as leading cause of cancer</field>
+        <field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field>
+    </object>
+</django-objects>
\ No newline at end of file
Index: tests/modeltests/fixtures/fixtures/fixture3.xml
===================================================================
--- tests/modeltests/fixtures/fixtures/fixture3.xml	(revision 0)
+++ tests/modeltests/fixtures/fixtures/fixture3.xml	(revision 0)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+    <object pk="2" model="fixtures.article">
+        <field type="CharField" name="headline">Poker on TV is great!</field>
+        <field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field>
+    </object>
+    <object pk="5" model="fixtures.article">
+        <field type="CharField" name="headline">XML identified as leading cause of cancer</field>
+        <field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field>
+    </object>
+</django-objects>
\ No newline at end of file
Index: tests/modeltests/fixtures/models.py
===================================================================
--- tests/modeltests/fixtures/models.py	(revision 0)
+++ tests/modeltests/fixtures/models.py	(revision 0)
@@ -0,0 +1,84 @@
+"""
+39. Fixtures.
+
+Fixtures are a way of loading data into the database in bulk. Fixure data 
+can be stored in any serializable format (including JSON and XML). Fixtures 
+are identified by name, and are stored in either a directory named 'fixtures'
+in the application directory, on in one of the directories named in the 
+FIXTURE_DIRS setting.
+"""
+
+from django.db import models
+
+class Article(models.Model):
+    headline = models.CharField(maxlength=100, default='Default headline')
+    pub_date = models.DateTimeField()
+
+    def __str__(self):
+        return self.headline
+        
+    class Meta:
+        ordering = ('-pub_date', 'headline')
+        
+__test__ = {'API_TESTS': """
+>>> from django.core import management
+>>> from django.db.models import get_app
+
+# Syncdb introduces 1 initial data object from initial_data.json.
+>>> Article.objects.all()
+[<Article: Python program becomes self aware>]
+
+# Load fixture 1. Single JSON file, with two objects.
+>>> management.load_data(['fixture1.json'], verbosity=0)
+>>> Article.objects.all()
+[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
+
+# Load fixture 2. JSON file imported by default. Overwrites some existing objects
+>>> management.load_data(['fixture2.json'], verbosity=0)
+>>> Article.objects.all()
+[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
+
+# Load fixture 3, XML format. 
+>>> management.load_data(['fixture3.xml'], verbosity=0)
+>>> Article.objects.all()
+[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
+
+# Load a fixture that doesn't exist
+>>> management.load_data(['unknown.json'], verbosity=0)
+
+# object list is unaffected
+>>> Article.objects.all()
+[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
+
+# Reset the database representation of this app. This will delete all data.
+>>> management.flush(verbosity=0, interactive=False)
+>>> Article.objects.all()
+[<Article: Python program becomes self aware>]
+
+# Load fixture 1 again, using format discovery
+>>> management.load_data(['fixture1'], verbosity=0)
+>>> Article.objects.all()
+[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
+
+# Try to load fixture 2 using format discovery; this will fail
+# because there are two fixture2's in the fixtures directory 
+>>> management.load_data(['fixture2'], verbosity=0) # doctest: +ELLIPSIS
+Multiple fixtures named 'fixture2' in '.../fixtures'. Aborting.
+
+>>> Article.objects.all()
+[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
+
+# Dump the current contents of the database as a JSON fixture
+>>> management.dump_data(['fixtures'], format='json')
+[{"pk": "3", "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": "2", "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": "1", "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]
+"""}
+
+from django.test import TestCase
+
+class SampleTestCase(TestCase):
+    fixtures = ['fixture1.json', 'fixture2.json']
+        
+    def testClassFixtures(self):
+        "Check that test case has installed 4 fixture objects"
+        self.assertEqual(Article.objects.count(), 4)
+        self.assertEquals(str(Article.objects.all()), "[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]")
Index: tests/modeltests/test_client/management.py
===================================================================
--- tests/modeltests/test_client/management.py	(revision 4431)
+++ tests/modeltests/test_client/management.py	(working copy)
@@ -1,10 +0,0 @@
-from django.dispatch import dispatcher
-from django.db.models import signals
-import models as test_client_app
-from django.contrib.auth.models import User
-
-def setup_test(app, created_models, verbosity):
-    # Create a user account for the login-based tests
-    User.objects.create_user('testclient','testclient@example.com', 'password')
-
-dispatcher.connect(setup_test, sender=test_client_app, signal=signals.post_syncdb)

Property changes on: tests/modeltests/test_client/fixtures
___________________________________________________________________
Name: svn:ignore
   + *.pyc


Index: tests/modeltests/test_client/fixtures/testdata.json
===================================================================
--- tests/modeltests/test_client/fixtures/testdata.json	(revision 0)
+++ tests/modeltests/test_client/fixtures/testdata.json	(revision 0)
@@ -0,0 +1,20 @@
+[
+    {
+        "pk": "1", 
+        "model": "auth.user", 
+        "fields": {
+            "username": "testclient", 
+            "first_name": "Test", 
+            "last_name": "Client", 
+            "is_active": true, 
+            "is_superuser": false, 
+            "is_staff": false, 
+            "last_login": "2006-12-17 07:03:31", 
+            "groups": [], 
+            "user_permissions": [], 
+            "password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161", 
+            "email": "testclient@example.com", 
+            "date_joined": "2006-12-17 07:03:31"
+        }
+    }
+]
\ No newline at end of file
Index: tests/modeltests/test_client/models.py
===================================================================
--- tests/modeltests/test_client/models.py	(revision 4431)
+++ tests/modeltests/test_client/models.py	(working copy)
@@ -19,10 +19,11 @@
 rather than the HTML rendered to the end-user.
 
 """
-from django.test.client import Client
-import unittest
+from django.test import Client, TestCase
 
-class ClientTest(unittest.TestCase):
+class ClientTest(TestCase):
+    fixtures = ['testdata.json']
+    
     def setUp(self):
         "Set up test environment"
         self.client = Client()
Index: tests/urls.py
===================================================================
--- tests/urls.py	(revision 4431)
+++ tests/urls.py	(working copy)
@@ -6,5 +6,5 @@
 
     # Always provide the auth system login and logout views
     (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
-    (r'^accounts/logout/$', 'django.contrib.auth.views.login'),
+    (r'^accounts/logout/$', 'django.contrib.auth.views.logout'),
 )
