Removed support for custom SQL per deprecation timeline.
This commit is contained in:
parent
a420f83e7d
commit
4aa089a9a9
|
@ -233,7 +233,7 @@ class ManagementUtility(object):
|
||||||
subcommand_cls = self.fetch_command(cwords[0])
|
subcommand_cls = self.fetch_command(cwords[0])
|
||||||
# special case: add the names of installed apps to options
|
# special case: add the names of installed apps to options
|
||||||
if cwords[0] in ('dumpdata', 'sql', 'sqlall', 'sqlclear',
|
if cwords[0] in ('dumpdata', 'sql', 'sqlall', 'sqlclear',
|
||||||
'sqlcustom', 'sqlindexes', 'sqlmigrate', 'sqlsequencereset', 'test'):
|
'sqlindexes', 'sqlmigrate', 'sqlsequencereset', 'test'):
|
||||||
try:
|
try:
|
||||||
app_configs = apps.get_app_configs()
|
app_configs = apps.get_app_configs()
|
||||||
# Get the last part of the dotted path as the app name.
|
# Get the last part of the dotted path as the app name.
|
||||||
|
|
|
@ -45,9 +45,6 @@ class Command(BaseCommand):
|
||||||
"Django to create, modify, and delete the table"
|
"Django to create, modify, and delete the table"
|
||||||
)
|
)
|
||||||
yield "# Feel free to rename the models, but don't rename db_table values or field names."
|
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 sqlcustom [app_label]'"
|
|
||||||
yield "# into your database."
|
|
||||||
yield "from __future__ import unicode_literals"
|
yield "from __future__ import unicode_literals"
|
||||||
yield ''
|
yield ''
|
||||||
yield 'from %s import models' % self.db_module
|
yield 'from %s import models' % self.db_module
|
||||||
|
|
|
@ -4,14 +4,12 @@ from __future__ import unicode_literals
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
import time
|
import time
|
||||||
import traceback
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
from django.core.management.color import no_style
|
from django.core.management.sql import emit_post_migrate_signal, emit_pre_migrate_signal
|
||||||
from django.core.management.sql import custom_sql_for_model, emit_post_migrate_signal, emit_pre_migrate_signal
|
|
||||||
from django.db import connections, router, transaction, DEFAULT_DB_ALIAS
|
from django.db import connections, router, transaction, DEFAULT_DB_ALIAS
|
||||||
from django.db.migrations.executor import MigrationExecutor
|
from django.db.migrations.executor import MigrationExecutor
|
||||||
from django.db.migrations.loader import AmbiguityError
|
from django.db.migrations.loader import AmbiguityError
|
||||||
|
@ -47,7 +45,6 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
self.verbosity = options.get('verbosity')
|
self.verbosity = options.get('verbosity')
|
||||||
self.interactive = options.get('interactive')
|
self.interactive = options.get('interactive')
|
||||||
self.show_traceback = options.get('traceback')
|
|
||||||
|
|
||||||
# Import the 'management' module within each installed app, to register
|
# Import the 'management' module within each installed app, to register
|
||||||
# dispatcher events.
|
# dispatcher events.
|
||||||
|
@ -73,7 +70,7 @@ class Command(BaseCommand):
|
||||||
no_color=options.get('no_color'),
|
no_color=options.get('no_color'),
|
||||||
settings=options.get('settings'),
|
settings=options.get('settings'),
|
||||||
stdout=self.stdout,
|
stdout=self.stdout,
|
||||||
traceback=self.show_traceback,
|
traceback=options.get('traceback'),
|
||||||
verbosity=self.verbosity,
|
verbosity=self.verbosity,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -167,18 +164,6 @@ class Command(BaseCommand):
|
||||||
self.stdout.write(self.style.MIGRATE_HEADING("Synchronizing apps without migrations:"))
|
self.stdout.write(self.style.MIGRATE_HEADING("Synchronizing apps without migrations:"))
|
||||||
self.sync_apps(connection, executor.loader.unmigrated_apps)
|
self.sync_apps(connection, executor.loader.unmigrated_apps)
|
||||||
|
|
||||||
# The test runner requires us to flush after a syncdb but before migrations,
|
|
||||||
# so do that here.
|
|
||||||
if options.get("test_flush", False):
|
|
||||||
call_command(
|
|
||||||
'flush',
|
|
||||||
verbosity=max(self.verbosity - 1, 0),
|
|
||||||
interactive=False,
|
|
||||||
database=db,
|
|
||||||
reset_sequences=False,
|
|
||||||
inhibit_post_migrate=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Migrate!
|
# Migrate!
|
||||||
if self.verbosity >= 1:
|
if self.verbosity >= 1:
|
||||||
self.stdout.write(self.style.MIGRATE_HEADING("Running migrations:"))
|
self.stdout.write(self.style.MIGRATE_HEADING("Running migrations:"))
|
||||||
|
@ -299,41 +284,4 @@ class Command(BaseCommand):
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
# The connection may have been closed by a syncdb handler.
|
|
||||||
cursor = connection.cursor()
|
|
||||||
try:
|
|
||||||
# Install custom SQL for the app (but only if this
|
|
||||||
# is a model we've just created)
|
|
||||||
if self.verbosity >= 1:
|
|
||||||
self.stdout.write(" Installing custom SQL...\n")
|
|
||||||
for app_name, model_list in manifest.items():
|
|
||||||
for model in model_list:
|
|
||||||
if model in created_models:
|
|
||||||
custom_sql = custom_sql_for_model(model, no_style(), connection)
|
|
||||||
if custom_sql:
|
|
||||||
if self.verbosity >= 2:
|
|
||||||
self.stdout.write(
|
|
||||||
" Installing custom SQL for %s.%s model\n" %
|
|
||||||
(app_name, model._meta.object_name)
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
with transaction.atomic(using=connection.alias):
|
|
||||||
for sql in custom_sql:
|
|
||||||
cursor.execute(sql)
|
|
||||||
except Exception as e:
|
|
||||||
self.stderr.write(
|
|
||||||
" Failed to install custom SQL for %s.%s model: %s\n"
|
|
||||||
% (app_name, model._meta.object_name, e)
|
|
||||||
)
|
|
||||||
if self.show_traceback:
|
|
||||||
traceback.print_exc()
|
|
||||||
else:
|
|
||||||
if self.verbosity >= 3:
|
|
||||||
self.stdout.write(
|
|
||||||
" No custom SQL for %s.%s model\n" %
|
|
||||||
(app_name, model._meta.object_name)
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
return created_models
|
return created_models
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.db import connections, DEFAULT_DB_ALIAS
|
||||||
|
|
||||||
|
|
||||||
class Command(AppCommand):
|
class Command(AppCommand):
|
||||||
help = "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s)."
|
help = "Prints the CREATE TABLE and CREATE INDEX SQL statements for the given model module name(s)."
|
||||||
|
|
||||||
output_transaction = True
|
output_transaction = True
|
||||||
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.core.management.base import AppCommand
|
|
||||||
from django.core.management.sql import sql_custom
|
|
||||||
from django.db import connections, DEFAULT_DB_ALIAS
|
|
||||||
|
|
||||||
|
|
||||||
class Command(AppCommand):
|
|
||||||
help = "Prints the custom table modifying SQL statements for the given app name(s)."
|
|
||||||
|
|
||||||
output_transaction = True
|
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
|
||||||
super(Command, self).add_arguments(parser)
|
|
||||||
parser.add_argument('--database', default=DEFAULT_DB_ALIAS,
|
|
||||||
help='Nominates a database to print the SQL for. Defaults to the '
|
|
||||||
'"default" database.')
|
|
||||||
|
|
||||||
def handle_app_config(self, app_config, **options):
|
|
||||||
if app_config.models_module is None:
|
|
||||||
return
|
|
||||||
connection = connections[options['database']]
|
|
||||||
statements = sql_custom(app_config, self.style, connection)
|
|
||||||
return '\n'.join(statements)
|
|
|
@ -1,15 +1,10 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
import warnings
|
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.conf import settings
|
|
||||||
from django.core.management.base import CommandError
|
from django.core.management.base import CommandError
|
||||||
from django.db import models, router
|
from django.db import models, router
|
||||||
from django.utils.deprecation import RemovedInDjango19Warning
|
|
||||||
from django.utils.version import get_docs_version
|
from django.utils.version import get_docs_version
|
||||||
|
|
||||||
|
|
||||||
|
@ -140,21 +135,6 @@ def sql_flush(style, connection, only_django=False, reset_sequences=True, allow_
|
||||||
return statements
|
return statements
|
||||||
|
|
||||||
|
|
||||||
def sql_custom(app_config, style, connection):
|
|
||||||
"Returns a list of the custom table modifying SQL statements for the given app."
|
|
||||||
|
|
||||||
check_for_migrations(app_config, connection)
|
|
||||||
|
|
||||||
output = []
|
|
||||||
|
|
||||||
app_models = router.get_migratable_models(app_config, connection.alias)
|
|
||||||
|
|
||||||
for model in app_models:
|
|
||||||
output.extend(custom_sql_for_model(model, style, connection))
|
|
||||||
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
def sql_indexes(app_config, style, connection):
|
def sql_indexes(app_config, style, connection):
|
||||||
"Returns a list of the CREATE INDEX SQL statements for all models in the given app."
|
"Returns a list of the CREATE INDEX SQL statements for all models in the given app."
|
||||||
|
|
||||||
|
@ -184,7 +164,6 @@ def sql_all(app_config, style, connection):
|
||||||
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
|
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
|
||||||
return (
|
return (
|
||||||
sql_create(app_config, style, connection) +
|
sql_create(app_config, style, connection) +
|
||||||
sql_custom(app_config, style, connection) +
|
|
||||||
sql_indexes(app_config, style, connection)
|
sql_indexes(app_config, style, connection)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -205,43 +184,6 @@ def _split_statements(content):
|
||||||
return statements
|
return statements
|
||||||
|
|
||||||
|
|
||||||
def custom_sql_for_model(model, style, connection):
|
|
||||||
opts = model._meta
|
|
||||||
app_dirs = []
|
|
||||||
app_dir = apps.get_app_config(model._meta.app_label).path
|
|
||||||
app_dirs.append(os.path.normpath(os.path.join(app_dir, 'sql')))
|
|
||||||
|
|
||||||
# Deprecated location -- remove in Django 1.9
|
|
||||||
old_app_dir = os.path.normpath(os.path.join(app_dir, 'models/sql'))
|
|
||||||
if os.path.exists(old_app_dir):
|
|
||||||
warnings.warn("Custom SQL location '<app_label>/models/sql' is "
|
|
||||||
"deprecated, use '<app_label>/sql' instead.",
|
|
||||||
RemovedInDjango19Warning)
|
|
||||||
app_dirs.append(old_app_dir)
|
|
||||||
|
|
||||||
output = []
|
|
||||||
|
|
||||||
# Post-creation SQL should come before any initial SQL data is loaded.
|
|
||||||
# However, this should not be done for models that are unmanaged or
|
|
||||||
# for fields that are part of a parent model (via model inheritance).
|
|
||||||
if opts.managed:
|
|
||||||
post_sql_fields = [f for f in opts.local_fields if hasattr(f, 'post_create_sql')]
|
|
||||||
for f in post_sql_fields:
|
|
||||||
output.extend(f.post_create_sql(style, model._meta.db_table))
|
|
||||||
|
|
||||||
# Find custom SQL, if it's available.
|
|
||||||
backend_name = connection.settings_dict['ENGINE'].split('.')[-1]
|
|
||||||
sql_files = []
|
|
||||||
for app_dir in app_dirs:
|
|
||||||
sql_files.append(os.path.join(app_dir, "%s.%s.sql" % (opts.model_name, backend_name)))
|
|
||||||
sql_files.append(os.path.join(app_dir, "%s.sql" % opts.model_name))
|
|
||||||
for sql_file in sql_files:
|
|
||||||
if os.path.exists(sql_file):
|
|
||||||
with io.open(sql_file, encoding=settings.FILE_CHARSET) as fp:
|
|
||||||
output.extend(connection.ops.prepare_sql_script(fp.read(), _allow_fallback=True))
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
def emit_pre_migrate_signal(verbosity, interactive, db):
|
def emit_pre_migrate_signal(verbosity, interactive, db):
|
||||||
# Emit the pre_migrate signal for every application.
|
# Emit the pre_migrate signal for every application.
|
||||||
for app_config in apps.get_app_configs():
|
for app_config in apps.get_app_configs():
|
||||||
|
|
|
@ -366,7 +366,6 @@ class BaseDatabaseCreation(object):
|
||||||
verbosity=max(verbosity - 1, 0),
|
verbosity=max(verbosity - 1, 0),
|
||||||
interactive=False,
|
interactive=False,
|
||||||
database=self.connection.alias,
|
database=self.connection.alias,
|
||||||
test_flush=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# We then serialize the current state of the database into a string
|
# We then serialize the current state of the database into a string
|
||||||
|
|
|
@ -3,15 +3,7 @@ Providing initial data for models
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
It's sometimes useful to pre-populate your database with hard-coded data when
|
It's sometimes useful to pre-populate your database with hard-coded data when
|
||||||
you're first setting up an app. There's a couple of ways you can have Django
|
you're first setting up an app. You can provide initial data via fixtures.
|
||||||
automatically create this data: you can provide `initial data via fixtures`_, or
|
|
||||||
you can provide `initial data as SQL`_.
|
|
||||||
|
|
||||||
In general, using a fixture is a cleaner method since it's database-agnostic,
|
|
||||||
but initial SQL is also quite a bit more flexible.
|
|
||||||
|
|
||||||
.. _initial data as sql: `providing initial sql data`_
|
|
||||||
.. _initial data via fixtures: `providing initial data with fixtures`_
|
|
||||||
|
|
||||||
.. _initial-data-via-fixtures:
|
.. _initial-data-via-fixtures:
|
||||||
|
|
||||||
|
@ -91,77 +83,3 @@ directories.
|
||||||
|
|
||||||
Fixtures are also used by the :ref:`testing framework
|
Fixtures are also used by the :ref:`testing framework
|
||||||
<topics-testing-fixtures>` to help set up a consistent test environment.
|
<topics-testing-fixtures>` to help set up a consistent test environment.
|
||||||
|
|
||||||
.. _initial-sql:
|
|
||||||
|
|
||||||
Providing initial SQL data
|
|
||||||
==========================
|
|
||||||
|
|
||||||
.. deprecated:: 1.7
|
|
||||||
|
|
||||||
If an application uses migrations, there is no loading of initial SQL data
|
|
||||||
(including backend-specific SQL data). Since migrations will be required
|
|
||||||
for applications in Django 1.9, this behavior is considered deprecated.
|
|
||||||
If you want to use initial SQL for an app, consider doing it in a
|
|
||||||
:ref:`data migration <data-migrations>`.
|
|
||||||
|
|
||||||
Django provides a hook for passing the database arbitrary SQL that's executed
|
|
||||||
just after the CREATE TABLE statements when you run :djadmin:`migrate`. You can
|
|
||||||
use this hook to populate default records, or you could also create SQL
|
|
||||||
functions, views, triggers, etc.
|
|
||||||
|
|
||||||
The hook is simple: Django just looks for a file called ``sql/<modelname>.sql``,
|
|
||||||
in your app directory, where ``<modelname>`` is the model's name in lowercase.
|
|
||||||
|
|
||||||
So, if you had a ``Person`` model in an app called ``myapp``, you could add
|
|
||||||
arbitrary SQL to the file ``sql/person.sql`` inside your ``myapp`` directory.
|
|
||||||
Here's an example of what the file might contain:
|
|
||||||
|
|
||||||
.. code-block:: sql
|
|
||||||
|
|
||||||
INSERT INTO myapp_person (first_name, last_name) VALUES ('John', 'Lennon');
|
|
||||||
INSERT INTO myapp_person (first_name, last_name) VALUES ('Paul', 'McCartney');
|
|
||||||
|
|
||||||
Each SQL file, if given, is expected to contain valid SQL statements
|
|
||||||
which will insert the desired data (e.g., properly-formatted
|
|
||||||
``INSERT`` statements separated by semicolons).
|
|
||||||
|
|
||||||
The SQL files are read by the :djadmin:`sqlcustom` and :djadmin:`sqlall`
|
|
||||||
commands in :doc:`manage.py </ref/django-admin>`. Refer to the :doc:`manage.py
|
|
||||||
documentation </ref/django-admin>` for more information.
|
|
||||||
|
|
||||||
Note that if you have multiple SQL data files, there's no guarantee of
|
|
||||||
the order in which they're executed. The only thing you can assume is
|
|
||||||
that, by the time your custom data files are executed, all the
|
|
||||||
database tables already will have been created.
|
|
||||||
|
|
||||||
.. admonition:: Initial SQL data and testing
|
|
||||||
|
|
||||||
This technique *cannot* be used to provide initial data for
|
|
||||||
testing purposes. Django's test framework flushes the contents of
|
|
||||||
the test database after each test; as a result, any data added
|
|
||||||
using the custom SQL hook will be lost.
|
|
||||||
|
|
||||||
If you require data for a test case, you should add it using
|
|
||||||
either a :ref:`test fixture <topics-testing-fixtures>`, or
|
|
||||||
programmatically add it during the ``setUp()`` of your test case.
|
|
||||||
|
|
||||||
Database-backend-specific SQL data
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
There's also a hook for backend-specific SQL data. For example, you
|
|
||||||
can have separate initial-data files for PostgreSQL and SQLite. For
|
|
||||||
each app, Django looks for a file called
|
|
||||||
``<app_label>/sql/<modelname>.<backend>.sql``, where ``<app_label>`` is
|
|
||||||
your app directory, ``<modelname>`` is the model's name in lowercase
|
|
||||||
and ``<backend>`` is the last part of the module name provided for the
|
|
||||||
:setting:`ENGINE <DATABASE-ENGINE>` in your settings file (e.g., if you have
|
|
||||||
defined a database with an :setting:`ENGINE <DATABASE-ENGINE>` value of
|
|
||||||
``django.db.backends.sqlite3``, Django will look for
|
|
||||||
``<app_label>/sql/<modelname>.sqlite3.sql``).
|
|
||||||
|
|
||||||
Backend-specific SQL data is executed before non-backend-specific SQL
|
|
||||||
data. For example, if your app contains the files ``sql/person.sql``
|
|
||||||
and ``sql/person.sqlite3.sql`` and you're installing the app on
|
|
||||||
SQLite, Django will execute the contents of
|
|
||||||
``sql/person.sqlite3.sql`` first, then ``sql/person.sql``.
|
|
||||||
|
|
|
@ -543,9 +543,7 @@ Now, run :djadmin:`migrate` again to create those model tables in your database:
|
||||||
Apply all migrations: polls
|
Apply all migrations: polls
|
||||||
Synchronizing apps without migrations:
|
Synchronizing apps without migrations:
|
||||||
Creating tables...
|
Creating tables...
|
||||||
Installing custom SQL...
|
|
||||||
Installing indexes...
|
Installing indexes...
|
||||||
Installed 0 object(s) from 0 fixture(s)
|
|
||||||
Running migrations:
|
Running migrations:
|
||||||
Applying polls.0001_initial... OK
|
Applying polls.0001_initial... OK
|
||||||
|
|
||||||
|
|
|
@ -84,9 +84,6 @@ given model module name(s).
|
||||||
.BI "sqlclear [" "app_label ..." "]"
|
.BI "sqlclear [" "app_label ..." "]"
|
||||||
Prints the DROP TABLE SQL statements for the given app name(s).
|
Prints the DROP TABLE SQL statements for the given app name(s).
|
||||||
.TP
|
.TP
|
||||||
.BI "sqlcustom [" "app_label ..." "]"
|
|
||||||
Prints the custom SQL statements for the given app name(s).
|
|
||||||
.TP
|
|
||||||
.BI "sqlflush [" "app_label ..." "]"
|
.BI "sqlflush [" "app_label ..." "]"
|
||||||
Prints the SQL statements that would be executed for the "flush" command.
|
Prints the SQL statements that would be executed for the "flush" command.
|
||||||
.TP
|
.TP
|
||||||
|
|
|
@ -989,9 +989,6 @@ sqlall <app_label app_label ...>
|
||||||
|
|
||||||
Prints the CREATE TABLE and initial-data SQL statements for the given app name(s).
|
Prints the CREATE TABLE and initial-data SQL statements for the given app name(s).
|
||||||
|
|
||||||
Refer to the description of :djadmin:`sqlcustom` for an explanation of how to
|
|
||||||
specify initial data.
|
|
||||||
|
|
||||||
The :djadminopt:`--database` option can be used to specify the database for
|
The :djadminopt:`--database` option can be used to specify the database for
|
||||||
which to print the SQL.
|
which to print the SQL.
|
||||||
|
|
||||||
|
@ -1012,30 +1009,6 @@ Prints the DROP TABLE SQL statements for the given app name(s).
|
||||||
The :djadminopt:`--database` option can be used to specify the database for
|
The :djadminopt:`--database` option can be used to specify the database for
|
||||||
which to print the SQL.
|
which to print the SQL.
|
||||||
|
|
||||||
sqlcustom <app_label app_label ...>
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. django-admin:: sqlcustom
|
|
||||||
|
|
||||||
Prints the custom SQL statements for the given app name(s).
|
|
||||||
|
|
||||||
For each model in each specified app, this command looks for the file
|
|
||||||
``<app_label>/sql/<modelname>.sql``, where ``<app_label>`` is the given app
|
|
||||||
name and ``<modelname>`` is the model's name in lowercase. For example, if you
|
|
||||||
have an app ``news`` that includes a ``Story`` model, ``sqlcustom`` will
|
|
||||||
attempt to read a file ``news/sql/story.sql`` and append it to the output of
|
|
||||||
this command.
|
|
||||||
|
|
||||||
Each of the SQL files, if given, is expected to contain valid SQL. The SQL
|
|
||||||
files are piped directly into the database after all of the models'
|
|
||||||
table-creation statements have been executed. Use this SQL hook to make any
|
|
||||||
table modifications, or insert any SQL functions into the database.
|
|
||||||
|
|
||||||
Note that the order in which the SQL files are processed is undefined.
|
|
||||||
|
|
||||||
The :djadminopt:`--database` option can be used to specify the database for
|
|
||||||
which to print the SQL.
|
|
||||||
|
|
||||||
sqldropindexes <app_label app_label ...>
|
sqldropindexes <app_label app_label ...>
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -1295,8 +1295,7 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
|
||||||
|
|
||||||
Take no action. If your database backend enforces referential
|
Take no action. If your database backend enforces referential
|
||||||
integrity, this will cause an :exc:`~django.db.IntegrityError` unless
|
integrity, this will cause an :exc:`~django.db.IntegrityError` unless
|
||||||
you manually add an SQL ``ON DELETE`` constraint to the database field
|
you manually add an SQL ``ON DELETE`` constraint to the database field.
|
||||||
(perhaps using :ref:`initial sql<initial-sql>`).
|
|
||||||
|
|
||||||
.. attribute:: ForeignKey.swappable
|
.. attribute:: ForeignKey.swappable
|
||||||
|
|
||||||
|
|
|
@ -738,7 +738,7 @@ Management Commands
|
||||||
* :djadmin:`collectstatic` command with symlink option is now supported on
|
* :djadmin:`collectstatic` command with symlink option is now supported on
|
||||||
Windows NT 6 (Windows Vista and newer).
|
Windows NT 6 (Windows Vista and newer).
|
||||||
|
|
||||||
* :ref:`initial-sql` now works better if the sqlparse_ Python library is
|
* Initial SQL data now works better if the sqlparse_ Python library is
|
||||||
installed.
|
installed.
|
||||||
|
|
||||||
Note that it's deprecated in favor of the
|
Note that it's deprecated in favor of the
|
||||||
|
@ -1517,8 +1517,8 @@ Custom SQL location for models package
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Previously, if models were organized in a package (``myapp/models/``) rather
|
Previously, if models were organized in a package (``myapp/models/``) rather
|
||||||
than simply ``myapp/models.py``, Django would look for :ref:`initial SQL data
|
than simply ``myapp/models.py``, Django would look for initial SQL data in
|
||||||
<initial-sql>` in ``myapp/models/sql/``. This bug has been fixed so that Django
|
``myapp/models/sql/``. This bug has been fixed so that Django
|
||||||
will search ``myapp/sql/`` as documented. After this issue was fixed, migrations
|
will search ``myapp/sql/`` as documented. After this issue was fixed, migrations
|
||||||
were added which deprecates initial SQL data. Thus, while this change still
|
were added which deprecates initial SQL data. Thus, while this change still
|
||||||
exists, the deprecation is irrelevant as the entire feature will be removed in
|
exists, the deprecation is irrelevant as the entire feature will be removed in
|
||||||
|
|
|
@ -585,7 +585,6 @@ Springmeyer
|
||||||
sql
|
sql
|
||||||
sqlall
|
sqlall
|
||||||
sqlclear
|
sqlclear
|
||||||
sqlcustom
|
|
||||||
sqldropindexes
|
sqldropindexes
|
||||||
sqlflush
|
sqlflush
|
||||||
sqlindexes
|
sqlindexes
|
||||||
|
|
|
@ -140,9 +140,7 @@ database to make sure they work as expected::
|
||||||
Apply all migrations: books
|
Apply all migrations: books
|
||||||
Synchronizing apps without migrations:
|
Synchronizing apps without migrations:
|
||||||
Creating tables...
|
Creating tables...
|
||||||
Installing custom SQL...
|
|
||||||
Installing indexes...
|
Installing indexes...
|
||||||
Installed 0 object(s) from 0 fixture(s)
|
|
||||||
Running migrations:
|
Running migrations:
|
||||||
Applying books.0003_auto... OK
|
Applying books.0003_auto... OK
|
||||||
|
|
||||||
|
|
|
@ -984,15 +984,6 @@ The most straightforward way of creating a fixture is to use the
|
||||||
already have some data in your database. See the :djadmin:`dumpdata
|
already have some data in your database. See the :djadmin:`dumpdata
|
||||||
documentation<dumpdata>` for more details.
|
documentation<dumpdata>` for more details.
|
||||||
|
|
||||||
.. admonition:: Initial SQL data and testing
|
|
||||||
|
|
||||||
Django provides a second way to insert initial data into models --
|
|
||||||
the :ref:`custom SQL hook <initial-sql>`. However, this technique
|
|
||||||
*cannot* be used to provide initial data for testing purposes.
|
|
||||||
Django's test framework flushes the contents of the test database
|
|
||||||
after each test; as a result, any data added using the custom SQL
|
|
||||||
hook will be lost.
|
|
||||||
|
|
||||||
Once you've created a fixture and placed it in a ``fixtures`` directory in one
|
Once you've created a fixture and placed it in a ``fixtures`` directory in one
|
||||||
of your :setting:`INSTALLED_APPS`, you can use it in your unit tests by
|
of your :setting:`INSTALLED_APPS`, you can use it in your unit tests by
|
||||||
specifying a ``fixtures`` class attribute on your :class:`django.test.TestCase`
|
specifying a ``fixtures`` class attribute on your :class:`django.test.TestCase`
|
||||||
|
|
|
@ -1386,7 +1386,6 @@ class CommandTypes(AdminScriptTestCase):
|
||||||
out, err = self.run_manage(args)
|
out, err = self.run_manage(args)
|
||||||
self.assertNoOutput(err)
|
self.assertNoOutput(err)
|
||||||
self.assertOutput(out, "Checks the entire Django project for potential problems.")
|
self.assertOutput(out, "Checks the entire Django project for potential problems.")
|
||||||
self.assertEqual(out.count('optional arguments'), 1)
|
|
||||||
|
|
||||||
def test_color_style(self):
|
def test_color_style(self):
|
||||||
style = color.no_style()
|
style = color.no_style()
|
||||||
|
|
|
@ -78,7 +78,7 @@ class BashCompletionTests(unittest.TestCase):
|
||||||
"Subcommands can be autocompleted"
|
"Subcommands can be autocompleted"
|
||||||
self._user_input('django-admin sql')
|
self._user_input('django-admin sql')
|
||||||
output = self._run_autocomplete()
|
output = self._run_autocomplete()
|
||||||
self.assertEqual(output, ['sql sqlall sqlclear sqlcustom sqldropindexes sqlflush sqlindexes sqlmigrate sqlsequencereset'])
|
self.assertEqual(output, ['sql sqlall sqlclear sqldropindexes sqlflush sqlindexes sqlmigrate sqlsequencereset'])
|
||||||
|
|
||||||
def test_completed_subcommand(self):
|
def test_completed_subcommand(self):
|
||||||
"Show option flags in case a subcommand is completed"
|
"Show option flags in case a subcommand is completed"
|
||||||
|
|
|
@ -13,10 +13,3 @@ class Article(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'fixtures_model_package'
|
app_label = 'fixtures_model_package'
|
||||||
ordering = ('-pub_date', 'headline')
|
ordering = ('-pub_date', 'headline')
|
||||||
|
|
||||||
|
|
||||||
class Book(models.Model):
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ('name',)
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
-- Deprecated search path for custom SQL -- remove in Django 1.9
|
|
||||||
INSERT INTO fixtures_model_package_book (name) VALUES ('My Deprecated Book');
|
|
|
@ -1 +0,0 @@
|
||||||
INSERT INTO fixtures_model_package_book (name) VALUES ('My Book');
|
|
|
@ -4,7 +4,6 @@ import warnings
|
||||||
|
|
||||||
from django.core import management
|
from django.core import management
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils.six import StringIO
|
|
||||||
|
|
||||||
from .models import Article
|
from .models import Article
|
||||||
|
|
||||||
|
@ -66,18 +65,3 @@ class FixtureTestCase(TestCase):
|
||||||
],
|
],
|
||||||
lambda a: a.headline,
|
lambda a: a.headline,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class InitialSQLTests(TestCase):
|
|
||||||
|
|
||||||
def test_custom_sql(self):
|
|
||||||
"""
|
|
||||||
#14300 -- Verify that custom_sql_for_model searches `app/sql` and not
|
|
||||||
`app/models/sql` (the old location will work until Django 1.9)
|
|
||||||
"""
|
|
||||||
out = StringIO()
|
|
||||||
management.call_command("sqlcustom", "fixtures_model_package", stdout=out)
|
|
||||||
output = out.getvalue()
|
|
||||||
self.assertIn("INSERT INTO fixtures_model_package_book (name) VALUES ('My Book')", output)
|
|
||||||
# value from deprecated search path models/sql (remove in Django 1.9)
|
|
||||||
self.assertIn("Deprecated Book", output)
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
"""
|
|
||||||
Regression tests for initial SQL insertion.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class Simple(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
|
@ -1,12 +0,0 @@
|
||||||
-- a comment
|
|
||||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('John'); -- another comment
|
|
||||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('-- Comment Man');
|
|
||||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('Paul');
|
|
||||||
INSERT INTO
|
|
||||||
initial_sql_regress_simple (name) VALUES ('Ringo');
|
|
||||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('George');
|
|
||||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('Miles O''Brien');
|
|
||||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('Semicolon;Man');
|
|
||||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('"100%" of % are not placeholders');
|
|
||||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('This line has a Windows line ending');
|
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
from django.core.management.color import no_style
|
|
||||||
from django.core.management.sql import custom_sql_for_model
|
|
||||||
from django.db import connections, DEFAULT_DB_ALIAS
|
|
||||||
from django.test import TestCase, override_settings
|
|
||||||
|
|
||||||
from .models import Simple
|
|
||||||
|
|
||||||
|
|
||||||
class InitialSQLTests(TestCase):
|
|
||||||
"""
|
|
||||||
The format of the included SQL file for this test suite is important.
|
|
||||||
It must end with a trailing newline in order to test the fix for #2161.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_initial_sql(self):
|
|
||||||
"""
|
|
||||||
As pointed out by #14661, test data loaded by custom SQL
|
|
||||||
can't be relied upon; as a result, the test framework flushes the
|
|
||||||
data contents before every test. This test validates that this has
|
|
||||||
occurred.
|
|
||||||
"""
|
|
||||||
self.assertEqual(Simple.objects.count(), 0)
|
|
||||||
|
|
||||||
def test_custom_sql(self):
|
|
||||||
"""
|
|
||||||
Simulate the custom SQL loading by migrate.
|
|
||||||
"""
|
|
||||||
connection = connections[DEFAULT_DB_ALIAS]
|
|
||||||
custom_sql = custom_sql_for_model(Simple, no_style(), connection)
|
|
||||||
with connection.cursor() as cursor:
|
|
||||||
for sql in custom_sql:
|
|
||||||
cursor.execute(sql)
|
|
||||||
self.assertEqual(Simple.objects.count(), 9)
|
|
||||||
self.assertEqual(
|
|
||||||
Simple.objects.get(name__contains='placeholders').name,
|
|
||||||
'"100%" of % are not placeholders'
|
|
||||||
)
|
|
||||||
|
|
||||||
@override_settings(DEBUG=True)
|
|
||||||
def test_custom_sql_debug(self):
|
|
||||||
"""
|
|
||||||
Same test, ensure that CursorDebugWrapper doesn't alter sql loading
|
|
||||||
(#3485).
|
|
||||||
"""
|
|
||||||
self.test_custom_sql()
|
|
Loading…
Reference in New Issue