1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

[soc2009/multidb] Modified the fixture loading, fixture dumping and synchronization process to be multi-db aware. Patch from Russell Keith-Magee.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11763 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2009-11-23 16:42:38 +00:00
parent 1fc8f9a279
commit 0c167ae0ff
14 changed files with 317 additions and 188 deletions

4
TODO
View File

@ -13,10 +13,6 @@ Required for v1.2
* Resolve the public facing UI issues around using multi-db * Resolve the public facing UI issues around using multi-db
* Should we take the opportunity to modify DB backends to use fully qualified paths? * Should we take the opportunity to modify DB backends to use fully qualified paths?
* Meta.using? Is is still required/desirable? * Meta.using? Is is still required/desirable?
* syncdb
* Add --exclude/--include argument? (not sure this approach will work due to flush)
* Flush - which models are flushed?
* Fixture loading over multiple DBs
* Testing infrastructure * Testing infrastructure
* Most tests don't need multidb. Some absolutely require it, but only to prove you * Most tests don't need multidb. Some absolutely require it, but only to prove you
can write to a different db. Second DB could be a SQLite temp file. Need to have can write to a different db. Second DB could be a SQLite temp file. Need to have

View File

@ -10,9 +10,9 @@ class Command(LabelCommand):
option_list = LabelCommand.option_list + ( option_list = LabelCommand.option_list + (
make_option('--database', action='store', dest='database', make_option('--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, help='Nominates a specific database to ' default=DEFAULT_DB_ALIAS, help='Nominates a database onto '
'install the cache table to. Defaults to the "default" ' 'which the cache table will be installed. '
'database.'), 'Defaults to the "default" database.'),
) )
requires_model_validation = False requires_model_validation = False

View File

@ -9,8 +9,8 @@ class Command(BaseCommand):
option_list = BaseCommand.option_list + ( option_list = BaseCommand.option_list + (
make_option('--database', action='store', dest='database', make_option('--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, help='Nominates a database to open a ' default=DEFAULT_DB_ALIAS, help='Nominates a database onto which to '
'shell for. Defaults to the "default" database.'), 'open a shell. Defaults to the "default" database.'),
) )
requires_model_validation = False requires_model_validation = False

View File

@ -1,6 +1,7 @@
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.core import serializers from django.core import serializers
from django.db import connections, DEFAULT_DB_ALIAS
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from optparse import make_option from optparse import make_option
@ -11,6 +12,9 @@ class Command(BaseCommand):
help='Specifies the output serialization format for fixtures.'), help='Specifies the output serialization format for fixtures.'),
make_option('--indent', default=None, dest='indent', type='int', make_option('--indent', default=None, dest='indent', type='int',
help='Specifies the indent level to use when pretty-printing output'), help='Specifies the indent level to use when pretty-printing output'),
make_option('--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, help='Nominates a specific database to load '
'fixtures into. Defaults to the "default" database.'),
make_option('-e', '--exclude', dest='exclude',action='append', default=[], make_option('-e', '--exclude', dest='exclude',action='append', default=[],
help='App to exclude (use multiple --exclude to exclude multiple apps).'), help='App to exclude (use multiple --exclude to exclude multiple apps).'),
) )
@ -22,6 +26,8 @@ class Command(BaseCommand):
format = options.get('format','json') format = options.get('format','json')
indent = options.get('indent',None) indent = options.get('indent',None)
using = options['database']
connection = connections[using]
exclude = options.get('exclude',[]) exclude = options.get('exclude',[])
show_traceback = options.get('traceback', False) show_traceback = options.get('traceback', False)
@ -67,14 +73,18 @@ class Command(BaseCommand):
except KeyError: except KeyError:
raise CommandError("Unknown serialization format: %s" % format) raise CommandError("Unknown serialization format: %s" % format)
# Get a list of synchronized tables
tables = connection.introspection.table_names()
objects = [] objects = []
for app, model_list in app_list.items(): for app, model_list in app_list.items():
if model_list is None: if model_list is None:
model_list = get_models(app) model_list = get_models(app)
for model in model_list: for model in model_list:
if not model._meta.proxy: # Don't serialize proxy models, or models that haven't been synchronized
objects.extend(model._default_manager.all()) if not model._meta.proxy and model._meta.db_table in tables:
objects.extend(model._default_manager.using(using).all())
try: try:
return serializers.serialize(format, objects, indent=indent) return serializers.serialize(format, objects, indent=indent)

View File

@ -1,7 +1,7 @@
from optparse import make_option from optparse import make_option
from django.conf import settings from django.conf import settings
from django.db import connections, transaction, models from django.db import connections, transaction, models, DEFAULT_DB_ALIAS
from django.core.management import call_command from django.core.management import call_command
from django.core.management.base import NoArgsCommand, CommandError from django.core.management.base import NoArgsCommand, CommandError
from django.core.management.color import no_style from django.core.management.color import no_style
@ -15,8 +15,8 @@ class Command(NoArgsCommand):
make_option('--noinput', action='store_false', dest='interactive', default=True, make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'), help='Tells Django to NOT prompt the user for input of any kind.'),
make_option('--database', action='store', dest='database', make_option('--database', action='store', dest='database',
default=None, help='Nominates a database to flush. Defaults to ' default=DEFAULT_DB_ALIAS, help='Nominates a database to flush. '
'flushing all databases.'), 'Defaults to the "default" database.'),
) )
help = "Executes ``sqlflush`` on the current database." help = "Executes ``sqlflush`` on the current database."

View File

@ -10,7 +10,7 @@ from django.core.management.base import BaseCommand
from django.core.management.color import no_style from django.core.management.color import no_style
from django.db import connections, transaction, DEFAULT_DB_ALIAS from django.db import connections, transaction, DEFAULT_DB_ALIAS
from django.db.models import get_apps from django.db.models import get_apps
from django.utils.itercompat import product
try: try:
set set
@ -30,11 +30,15 @@ class Command(BaseCommand):
option_list = BaseCommand.option_list + ( option_list = BaseCommand.option_list + (
make_option('--database', action='store', dest='database', make_option('--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, help='Nominates a specific database to load ' default=DEFAULT_DB_ALIAS, help='Nominates a specific database to load '
'fixtures into. By default uses the "default" database.'), 'fixtures into. Defaults to the "default" database.'),
make_option('-e', '--exclude', dest='exclude',action='append', default=[],
help='App to exclude (use multiple --exclude to exclude multiple apps).'),
) )
def handle(self, *fixture_labels, **options): def handle(self, *fixture_labels, **options):
using = options['database'] using = options['database']
excluded_apps = options.get('exclude', [])
connection = connections[using] connection = connections[using]
self.style = no_style() self.style = no_style()
@ -125,73 +129,75 @@ class Command(BaseCommand):
print "Checking %s for fixtures..." % humanize(fixture_dir) print "Checking %s for fixtures..." % humanize(fixture_dir)
label_found = False label_found = False
for format in formats: for combo in product([using, None], formats, compression_formats):
for compression_format in compression_formats: database, format, compression_format = combo
if compression_format: file_name = '.'.join(
file_name = '.'.join([fixture_name, format, p for p in [
compression_format]) fixture_name, database, format, compression_format
else: ]
file_name = '.'.join([fixture_name, format]) if p
)
if verbosity > 1: if verbosity > 1:
print "Trying %s for %s fixture '%s'..." % \ print "Trying %s for %s fixture '%s'..." % \
(humanize(fixture_dir), file_name, fixture_name) (humanize(fixture_dir), file_name, fixture_name)
full_path = os.path.join(fixture_dir, file_name) full_path = os.path.join(fixture_dir, file_name)
open_method = compression_types[compression_format] open_method = compression_types[compression_format]
try: try:
fixture = open_method(full_path, 'r') fixture = open_method(full_path, 'r')
if label_found: if label_found:
fixture.close() fixture.close()
print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." % print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
(fixture_name, humanize(fixture_dir))) (fixture_name, humanize(fixture_dir)))
transaction.rollback(using=using) transaction.rollback(using=using)
transaction.leave_transaction_management(using=using) transaction.leave_transaction_management(using=using)
return return
else: else:
fixture_count += 1 fixture_count += 1
objects_in_fixture = 0 objects_in_fixture = 0
if verbosity > 0: if verbosity > 0:
print "Installing %s fixture '%s' from %s." % \ print "Installing %s fixture '%s' from %s." % \
(format, fixture_name, humanize(fixture_dir)) (format, fixture_name, humanize(fixture_dir))
try: try:
objects = serializers.deserialize(format, fixture) objects = serializers.deserialize(format, fixture)
for obj in objects: for obj in objects:
if obj.object._meta.app_label not in excluded_apps:
objects_in_fixture += 1 objects_in_fixture += 1
models.add(obj.object.__class__) models.add(obj.object.__class__)
obj.save(using=using) obj.save(using=using)
object_count += objects_in_fixture object_count += objects_in_fixture
label_found = True label_found = True
except (SystemExit, KeyboardInterrupt): except (SystemExit, KeyboardInterrupt):
raise raise
except Exception: except Exception:
import traceback import traceback
fixture.close()
transaction.rollback(using=using)
transaction.leave_transaction_management(using=using)
if show_traceback:
traceback.print_exc()
else:
sys.stderr.write(
self.style.ERROR("Problem installing fixture '%s': %s\n" %
(full_path, ''.join(traceback.format_exception(sys.exc_type,
sys.exc_value, sys.exc_traceback)))))
return
fixture.close() fixture.close()
transaction.rollback(using=using)
# If the fixture we loaded contains 0 objects, assume that an transaction.leave_transaction_management(using=using)
# error was encountered during fixture loading. if show_traceback:
if objects_in_fixture == 0: traceback.print_exc()
else:
sys.stderr.write( sys.stderr.write(
self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" % self.style.ERROR("Problem installing fixture '%s': %s\n" %
(fixture_name))) (full_path, ''.join(traceback.format_exception(sys.exc_type,
transaction.rollback(using=using) sys.exc_value, sys.exc_traceback)))))
transaction.leave_transaction_management(using=using) return
return fixture.close()
except Exception, e: # If the fixture we loaded contains 0 objects, assume that an
if verbosity > 1: # error was encountered during fixture loading.
print "No %s fixture '%s' in %s." % \ if objects_in_fixture == 0:
(format, fixture_name, humanize(fixture_dir)) sys.stderr.write(
self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" %
(fixture_name)))
transaction.rollback(using=using)
transaction.leave_transaction_management(using=using)
return
except Exception, e:
if verbosity > 1:
print "No %s fixture '%s' in %s." % \
(format, fixture_name, humanize(fixture_dir))
# If we found even one object in a fixture, we need to reset the # If we found even one object in a fixture, we need to reset the
# database sequences. # database sequences.

View File

@ -4,15 +4,15 @@ from django.conf import settings
from django.core.management.base import AppCommand, CommandError from django.core.management.base import AppCommand, CommandError
from django.core.management.color import no_style from django.core.management.color import no_style
from django.core.management.sql import sql_reset from django.core.management.sql import sql_reset
from django.db import connections, transaction from django.db import connections, transaction, DEFAULT_DB_ALIAS
class Command(AppCommand): class Command(AppCommand):
option_list = AppCommand.option_list + ( option_list = AppCommand.option_list + (
make_option('--noinput', action='store_false', dest='interactive', default=True, make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'), help='Tells Django to NOT prompt the user for input of any kind.'),
make_option('--database', action='store', dest='database', make_option('--database', action='store', dest='database',
default='', help='Nominates a database to reset. Defaults to ' default=DEFAULT_DB_ALIAS, help='Nominates a database to reset. '
'reseting all databases.'), 'Defaults to the "default" database.'),
) )
help = "Executes ``sqlreset`` for the given app(s) in the current database." help = "Executes ``sqlreset`` for the given app(s) in the current database."
args = '[appname ...]' args = '[appname ...]'
@ -20,42 +20,38 @@ class Command(AppCommand):
output_transaction = True output_transaction = True
def handle_app(self, app, **options): def handle_app(self, app, **options):
if not options['database']: using = options['database']
dbs = connections.all() connection = connections[using]
else:
dbs = [options['database']]
app_name = app.__name__.split('.')[-2] app_name = app.__name__.split('.')[-2]
self.style = no_style() self.style = no_style()
for connection in dbs: sql_list = sql_reset(app, self.style, connection)
sql_list = sql_reset(app, self.style, connection) if options.get('interactive'):
confirm = raw_input("""
You have requested a database reset.
This will IRREVERSIBLY DESTROY any data for
the "%s" application in the database "%s".
Are you sure you want to do this?
if options.get('interactive'): Type 'yes' to continue, or 'no' to cancel: """ % (app_name, connection.settings_dict['DATABASE_NAME']))
confirm = raw_input(""" else:
You have requested a database reset. confirm = 'yes'
This will IRREVERSIBLY DESTROY any data for
the "%s" application in the database "%s".
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: """ % (app_name, connection.settings_dict['DATABASE_NAME'])) if confirm == 'yes':
else: try:
confirm = 'yes' cursor = connection.cursor()
for sql in sql_list:
if confirm == 'yes': cursor.execute(sql)
try: except Exception, e:
cursor = connection.cursor() transaction.rollback_unless_managed()
for sql in sql_list: raise CommandError("""Error: %s couldn't be reset. Possible reasons:
cursor.execute(sql) * The database isn't running or isn't configured correctly.
except Exception, e: * At least one of the database tables doesn't exist.
transaction.rollback_unless_managed() * The SQL was invalid.
raise CommandError("""Error: %s couldn't be reset. Possible reasons: Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
* The database isn't running or isn't configured correctly. The full error: %s""" % (app_name, app_name, e))
* At least one of the database tables doesn't exist. transaction.commit_unless_managed()
* The SQL was invalid. else:
Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run. print "Reset cancelled."
The full error: %s""" % (app_name, app_name, e))
transaction.commit_unless_managed()
else:
print "Reset cancelled."

View File

@ -14,8 +14,10 @@ class Command(NoArgsCommand):
make_option('--noinput', action='store_false', dest='interactive', default=True, make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'), help='Tells Django to NOT prompt the user for input of any kind.'),
make_option('--database', action='store', dest='database', make_option('--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, help='Nominates a database to sync. ' default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. '
'Defaults to the "default" database.'), 'Defaults to the "default" database.'),
make_option('-e', '--exclude', dest='exclude',action='append', default=[],
help='App to exclude (use multiple --exclude to exclude multiple apps).'),
) )
help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created." help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
@ -24,6 +26,7 @@ class Command(NoArgsCommand):
verbosity = int(options.get('verbosity', 1)) verbosity = int(options.get('verbosity', 1))
interactive = options.get('interactive') interactive = options.get('interactive')
show_traceback = options.get('traceback', False) show_traceback = options.get('traceback', False)
exclude = options.get('exclude', [])
self.style = no_style() self.style = no_style()
@ -56,8 +59,11 @@ class Command(NoArgsCommand):
created_models = set() created_models = set()
pending_references = {} pending_references = {}
excluded_apps = [models.get_app(app_label) for app_label in exclude]
app_list = [app for app in models.get_apps() if app not in excluded_apps]
# Create the tables for each model # Create the tables for each model
for app in models.get_apps(): for app in app_list:
app_name = app.__name__.split('.')[-2] app_name = app.__name__.split('.')[-2]
model_list = models.get_models(app, include_auto_created=True) model_list = models.get_models(app, include_auto_created=True)
for model in model_list: for model in model_list:
@ -95,7 +101,7 @@ class Command(NoArgsCommand):
# Install custom SQL for the app (but only if this # Install custom SQL for the app (but only if this
# is a model we've just created) # is a model we've just created)
for app in models.get_apps(): for app in app_list:
app_name = app.__name__.split('.')[-2] app_name = app.__name__.split('.')[-2]
for model in models.get_models(app): for model in models.get_models(app):
if model in created_models: if model in created_models:
@ -118,8 +124,9 @@ class Command(NoArgsCommand):
else: else:
if verbosity >= 2: if verbosity >= 2:
print "No custom SQL for %s.%s model" % (app_name, model._meta.object_name) print "No custom SQL for %s.%s model" % (app_name, model._meta.object_name)
# Install SQL indicies for all newly created models # Install SQL indicies for all newly created models
for app in models.get_apps(): for app in app_list:
app_name = app.__name__.split('.')[-2] app_name = app.__name__.split('.')[-2]
for model in models.get_models(app): for model in models.get_models(app):
if model in created_models: if model in created_models:
@ -138,4 +145,4 @@ class Command(NoArgsCommand):
transaction.commit_unless_managed(using=db) transaction.commit_unless_managed(using=db)
from django.core.management import call_command from django.core.management import call_command
call_command('loaddata', 'initial_data', verbosity=verbosity, database=db) call_command('loaddata', 'initial_data', verbosity=verbosity, exclude=exclude, database=db)

View File

@ -45,6 +45,19 @@ def groupby(iterable, keyfunc=None):
l.append(item) l.append(item)
yield lastkey, l yield lastkey, l
def product(*args, **kwds):
"""
Taken from http://docs.python.org/library/itertools.html#itertools.product
"""
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = map(tuple, args) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
# Not really in itertools, since it's a builtin in Python 2.4 and later, but it # Not really in itertools, since it's a builtin in Python 2.4 and later, but it
# does operate as an iterator. # does operate as an iterator.
def reversed(data): def reversed(data):
@ -57,6 +70,8 @@ else:
tee = compat_tee tee = compat_tee
if hasattr(itertools, 'groupby'): if hasattr(itertools, 'groupby'):
groupby = itertools.groupby groupby = itertools.groupby
if hasattr(itertools, 'product'):
product = itertools.product
def is_iterable(x): def is_iterable(x):
"A implementation independent way of checking for iterables" "A implementation independent way of checking for iterables"

View File

@ -121,11 +121,10 @@ createcachetable
Creates a cache table named ``tablename`` for use with the database cache Creates a cache table named ``tablename`` for use with the database cache
backend. See :ref:`topics-cache` for more information. backend. See :ref:`topics-cache` for more information.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to install the cachetable to. By default uses the The :djadminopt:`--database` option can be used to specify the database
``'default'`` alias. onto which the cachetable will be installed.
createsuperuser createsuperuser
--------------- ---------------
@ -173,11 +172,10 @@ the program name (``psql``, ``mysql``, ``sqlite3``) will find the program in
the right place. There's no way to specify the location of the program the right place. There's no way to specify the location of the program
manually. manually.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to open the shell for. By default uses the The :djadminopt:`--database` option can be used to specify the database
``'default'`` alias. onto which to open a shell.
diffsettings diffsettings
@ -212,21 +210,6 @@ records to dump. If you're using a :ref:`custom manager <custom-managers>` as
the default manager and it filters some of the available records, not all of the the default manager and it filters some of the available records, not all of the
objects will be dumped. objects will be dumped.
.. django-admin-option:: --exclude
.. versionadded:: 1.0
Exclude a specific application from the applications whose contents is
output. For example, to specifically exclude the `auth` application from
the output, you would call::
django-admin.py dumpdata --exclude=auth
If you want to exclude multiple applications, use multiple ``--exclude``
directives::
django-admin.py dumpdata --exclude=auth --exclude=contenttypes
.. django-admin-option:: --format <fmt> .. django-admin-option:: --format <fmt>
By default, ``dumpdata`` will format its output in JSON, but you can use the By default, ``dumpdata`` will format its output in JSON, but you can use the
@ -239,6 +222,11 @@ By default, ``dumpdata`` will output all data on a single line. This isn't
easy for humans to read, so you can use the ``--indent`` option to easy for humans to read, so you can use the ``--indent`` option to
pretty-print the output with a number of indentation spaces. pretty-print the output with a number of indentation spaces.
.. versionadded:: 1.0
The :djadminopt:`--exclude` option may be provided to prevent specific
applications from being dumped.
.. versionadded:: 1.1 .. versionadded:: 1.1
In addition to specifying application names, you can provide a list of In addition to specifying application names, you can provide a list of
@ -247,6 +235,11 @@ name to ``dumpdata``, the dumped output will be restricted to that model,
rather than the entire application. You can also mix application names and rather than the entire application. You can also mix application names and
model names. model names.
.. versionadded:: 1.2
The :djadminopt:`--database` option can be used to specify the database
onto which the data will be loaded.
flush flush
----- -----
@ -260,10 +253,10 @@ fixture will be re-installed.
The :djadminopt:`--noinput` option may be provided to suppress all user The :djadminopt:`--noinput` option may be provided to suppress all user
prompts. prompts.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to flush. By default flushes all databases. The :djadminopt:`--database` option may be used to specify the database
to flush.
inspectdb inspectdb
@ -309,11 +302,10 @@ needed.
``inspectdb`` works with PostgreSQL, MySQL and SQLite. Foreign-key detection ``inspectdb`` works with PostgreSQL, MySQL and SQLite. Foreign-key detection
only works in PostgreSQL and with certain types of MySQL tables. only works in PostgreSQL and with certain types of MySQL tables.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to introspect. By default uses the ``'default'`` The :djadminopt:`--database` option may be used to specify the
alias. database to introspect.
loaddata <fixture fixture ...> loaddata <fixture fixture ...>
@ -323,6 +315,11 @@ loaddata <fixture fixture ...>
Searches for and loads the contents of the named fixture into the database. Searches for and loads the contents of the named fixture into the database.
.. versionadded:: 1.2
The :djadminopt:`--database` option can be used to specify the database
onto which the data will be loaded.
What's a "fixture"? What's a "fixture"?
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
@ -404,6 +401,37 @@ installation will be aborted, and any data installed in the call to
references in your data files - MySQL doesn't provide a mechanism to references in your data files - MySQL doesn't provide a mechanism to
defer checking of row constraints until a transaction is committed. defer checking of row constraints until a transaction is committed.
Database-specific fixtures
~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are in a multi-database setup, you may have fixture data that
you want to load onto one database, but not onto another. In this
situation, you can add database identifier into . If your
:setting:`DATABASES` setting has a 'master' database defined, you can
define the fixture ``mydata.master.json`` or
``mydata.master.json.gz``. This fixture will only be loaded if you
have specified that you want to load data onto the ``master``
database.
Excluding applications from loading
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.2
The :djadminopt:`--exclude` option may be provided to prevent specific
applications from being loaded.
For example, if you wanted to exclude models from ``django.contrib.auth``
from being loaded into your database, you would call::
django-admin.py loaddata mydata.json --exclude auth
This will look for for a JSON fixture called ``mydata`` in all the
usual locations - including the ``fixtures`` directory of the
``django.contrib.auth`` application. However, any fixture object that
identifies itself as belonging to the ``auth`` application (e.g.,
instance of ``auth.User``) would be ignored by loaddata.
makemessages makemessages
------------ ------------
@ -465,10 +493,10 @@ Executes the equivalent of ``sqlreset`` for the given app name(s).
The :djadminopt:`--noinput` option may be provided to suppress all user The :djadminopt:`--noinput` option may be provided to suppress all user
prompts. prompts.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to reset. By default resets all databases. The :djadminopt:`--database` option can be used to specify the alias
of the database to reset.
Executes the equivalent of ``sqlreset`` for the given app name(s). Executes the equivalent of ``sqlreset`` for the given app name(s).
@ -592,12 +620,10 @@ sql <appname appname ...>
Prints the CREATE TABLE SQL statements for the given app name(s). Prints the CREATE TABLE SQL statements for the given app name(s).
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to print the SQL for. By default uses the
``'default'`` alias.
The :djadminopt:`--database` option can be used to specify the database for
which to print the SQL.
sqlall <appname appname ...> sqlall <appname appname ...>
---------------------------- ----------------------------
@ -609,11 +635,10 @@ Prints the CREATE TABLE and initial-data SQL statements for the given app name(s
Refer to the description of ``sqlcustom`` for an explanation of how to Refer to the description of ``sqlcustom`` for an explanation of how to
specify initial data. specify initial data.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to print the SQL for. By default uses the The :djadminopt:`--database` option can be used to specify the database for
``'default'`` alias. which to print the SQL.
sqlclear <appname appname ...> sqlclear <appname appname ...>
------------------------------ ------------------------------
@ -622,11 +647,10 @@ sqlclear <appname appname ...>
Prints the DROP TABLE SQL statements for the given app name(s). Prints the DROP TABLE SQL statements for the given app name(s).
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to print the SQL for. By default uses the The :djadminopt:`--database` option can be used to specify the database for
``'default'`` alias. which to print the SQL.
sqlcustom <appname appname ...> sqlcustom <appname appname ...>
------------------------------- -------------------------------
@ -649,11 +673,10 @@ table modifications, or insert any SQL functions into the database.
Note that the order in which the SQL files are processed is undefined. Note that the order in which the SQL files are processed is undefined.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to print the SQL for. By default uses the The :djadminopt:`--database` option can be used to specify the database for
``'default'`` alias. which to print the SQL.
sqlflush sqlflush
-------- --------
@ -663,11 +686,10 @@ sqlflush
Prints the SQL statements that would be executed for the :djadmin:`flush` Prints the SQL statements that would be executed for the :djadmin:`flush`
command. command.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to print the SQL for. By default uses the The :djadminopt:`--database` option can be used to specify the database for
``'default'`` alias. which to print the SQL.
sqlindexes <appname appname ...> sqlindexes <appname appname ...>
-------------------------------- --------------------------------
@ -676,11 +698,10 @@ sqlindexes <appname appname ...>
Prints the CREATE INDEX SQL statements for the given app name(s). Prints the CREATE INDEX SQL statements for the given app name(s).
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to print the SQL for. By default uses the The :djadminopt:`--database` option can be used to specify the database for
``'default'`` alias. which to print the SQL.
sqlreset <appname appname ...> sqlreset <appname appname ...>
------------------------------ ------------------------------
@ -689,11 +710,10 @@ sqlreset <appname appname ...>
Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s). Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s).
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to print the SQL for. By default uses the The :djadminopt:`--database` option can be used to specify the database for
``'default'`` alias. which to print the SQL.
sqlsequencereset <appname appname ...> sqlsequencereset <appname appname ...>
-------------------------------------- --------------------------------------
@ -708,11 +728,10 @@ number for automatically incremented fields.
Use this command to generate SQL which will fix cases where a sequence is out Use this command to generate SQL which will fix cases where a sequence is out
of sync with its automatically incremented field data. of sync with its automatically incremented field data.
--database .. versionadded:: 1.2
~~~~~~~~~~
The alias for the database to print the SQL for. By default uses the The :djadminopt:`--database` option can be used to specify the database for
``'default'`` alias. which to print the SQL.
startapp <appname> startapp <appname>
------------------ ------------------
@ -770,17 +789,16 @@ with an appropriate extension (e.g. ``json`` or ``xml``). See the
documentation for ``loaddata`` for details on the specification of fixture documentation for ``loaddata`` for details on the specification of fixture
data files. data files.
--database
~~~~~~~~~~
The alias for the database install the tables for. By default uses the
``'default'`` alias.
--noinput --noinput
~~~~~~~~~ ~~~~~~~~~
The :djadminopt:`--noinput` option may be provided to suppress all user The :djadminopt:`--noinput` option may be provided to suppress all user
prompts. prompts.
.. versionadded:: 1.2
The :djadminopt:`--database` option can be used to specify the database to
synchronize.
test <app or test identifier> test <app or test identifier>
----------------------------- -----------------------------
@ -922,6 +940,30 @@ Common options
The following options are not available on every commands, but they are The following options are not available on every commands, but they are
common to a number of commands. common to a number of commands.
.. django-admin-option:: --database
.. versionadded:: 1.2
Used to specify the database on which a command will operate. If not
specified, this option will default to an alias of ``default``.
For example, to dump data from the database with the alias ``master``::
django-admin.py dumpdata --database=master
.. django-admin-option:: --exclude
Exclude a specific application from the applications whose contents is
output. For example, to specifically exclude the `auth` application from
the output of dumpdata, you would call::
django-admin.py dumpdata --exclude=auth
If you want to exclude multiple applications, use multiple ``--exclude``
directives::
django-admin.py dumpdata --exclude=auth --exclude=contenttypes
.. django-admin-option:: --locale .. django-admin-option:: --locale
Use the ``--locale`` or ``-l`` option to specify the locale to process. Use the ``--locale`` or ``-l`` option to specify the locale to process.

View File

@ -0,0 +1,10 @@
[
{
"pk": "6",
"model": "fixtures.article",
"fields": {
"headline": "Who needs more than one database?",
"pub_date": "2006-06-16 14:00:00"
}
}
]

View File

@ -0,0 +1,10 @@
[
{
"pk": "8",
"model": "fixtures.article",
"fields": {
"headline": "There is no spoon.",
"pub_date": "2006-06-16 14:00:00"
}
}
]

View File

@ -159,6 +159,43 @@ Multiple fixtures named 'fixture2' in '...fixtures'. Aborting.
>>> management.call_command('loaddata', 'fixture5', verbosity=0) # doctest: +ELLIPSIS >>> management.call_command('loaddata', 'fixture5', verbosity=0) # doctest: +ELLIPSIS
Multiple fixtures named 'fixture5' in '...fixtures'. Aborting. Multiple fixtures named 'fixture5' in '...fixtures'. Aborting.
>>> management.call_command('flush', verbosity=0, interactive=False)
# Load fixtures 6 and 7. These will load using the 'default' database identifier implicitly
>>> management.call_command('loaddata', 'fixture6', verbosity=0)
>>> management.call_command('loaddata', 'fixture7', verbosity=0)
>>> Article.objects.all()
[<Article: Who needs more than one database?>, <Article: Who needs to use compressed data?>, <Article: Python program becomes self aware>]
>>> management.call_command('flush', verbosity=0, interactive=False)
# Load fixtures 6 and 7. These will load using the 'default' database identifier explicitly
>>> management.call_command('loaddata', 'fixture6', verbosity=0, using='default')
>>> management.call_command('loaddata', 'fixture7', verbosity=0, using='default')
>>> Article.objects.all()
[<Article: Who needs more than one database?>, <Article: Who needs to use compressed data?>, <Article: Python program becomes self aware>]
>>> management.call_command('flush', verbosity=0, interactive=False)
# Try to load fixture 8. This won't load because the database identifier doesn't match
>>> management.call_command('loaddata', 'fixture8', verbosity=0)
>>> Article.objects.all()
[<Article: Python program becomes self aware>]
>>> management.call_command('loaddata', 'fixture8', verbosity=0, using='default')
>>> Article.objects.all()
[<Article: Python program becomes self aware>]
>>> management.call_command('flush', verbosity=0, interactive=False)
# Try to load fixture 1, but this time, exclude the 'fixtures' app.
>>> management.call_command('loaddata', 'fixture1', verbosity=0, exclude='fixtures')
>>> Article.objects.all()
[<Article: Python program becomes self aware>]
>>> Category.objects.all()
[]
""" """
from django.test import TestCase from django.test import TestCase