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:
parent
1fc8f9a279
commit
0c167ae0ff
4
TODO
4
TODO
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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."
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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."
|
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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.
|
||||||
|
10
tests/modeltests/fixtures/fixtures/fixture6.default.json
Normal file
10
tests/modeltests/fixtures/fixtures/fixture6.default.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
BIN
tests/modeltests/fixtures/fixtures/fixture7.default.json.gz
Normal file
BIN
tests/modeltests/fixtures/fixtures/fixture7.default.json.gz
Normal file
Binary file not shown.
10
tests/modeltests/fixtures/fixtures/fixture8.nosuchdb.json
Normal file
10
tests/modeltests/fixtures/fixtures/fixture8.nosuchdb.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"pk": "8",
|
||||||
|
"model": "fixtures.article",
|
||||||
|
"fields": {
|
||||||
|
"headline": "There is no spoon.",
|
||||||
|
"pub_date": "2006-06-16 14:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user