Fixed #14300 -- Fixed initial SQL location if models is a package.
Thanks al_the_x for the report and fheinz for the draft patch.
This commit is contained in:
parent
c928725b93
commit
31c13a99bb
|
@ -233,7 +233,7 @@ class Command(BaseCommand):
|
|||
"""
|
||||
dirs = []
|
||||
for path in get_app_paths():
|
||||
d = os.path.join(os.path.dirname(path), 'fixtures')
|
||||
d = os.path.join(path, 'fixtures')
|
||||
if os.path.isdir(d):
|
||||
dirs.append(d)
|
||||
dirs.extend(list(settings.FIXTURE_DIRS))
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
|||
import codecs
|
||||
import os
|
||||
import re
|
||||
import warnings
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import CommandError
|
||||
|
@ -168,7 +169,18 @@ def _split_statements(content):
|
|||
|
||||
def custom_sql_for_model(model, style, connection):
|
||||
opts = model._meta
|
||||
app_dir = os.path.normpath(os.path.join(os.path.dirname(upath(models.get_app(model._meta.app_label).__file__)), 'sql'))
|
||||
app_dirs = []
|
||||
app_dir = models.get_app_path(model._meta.app_label)
|
||||
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.",
|
||||
PendingDeprecationWarning)
|
||||
app_dirs.append(old_app_dir)
|
||||
|
||||
output = []
|
||||
|
||||
# Post-creation SQL should come before any initial SQL data is loaded.
|
||||
|
@ -181,8 +193,10 @@ def custom_sql_for_model(model, style, connection):
|
|||
|
||||
# Find custom SQL, if it's available.
|
||||
backend_name = connection.settings_dict['ENGINE'].split('.')[-1]
|
||||
sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.model_name, backend_name)),
|
||||
os.path.join(app_dir, "%s.sql" % opts.model_name)]
|
||||
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 codecs.open(sql_file, 'U', encoding=settings.FILE_CHARSET) as fp:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from functools import wraps
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
|
||||
from django.db.models.loading import get_apps, get_app_paths, get_app, get_models, get_model, register_models, UnavailableApp
|
||||
from django.db.models.loading import get_apps, get_app_path, get_app_paths, get_app, get_models, get_model, register_models, UnavailableApp
|
||||
from django.db.models.query import Q
|
||||
from django.db.models.expressions import F
|
||||
from django.db.models.manager import Manager
|
||||
|
|
|
@ -154,6 +154,16 @@ class AppCache(object):
|
|||
|
||||
return [elt[0] for elt in apps]
|
||||
|
||||
def _get_app_path(self, app):
|
||||
if hasattr(app, '__path__'): # models/__init__.py package
|
||||
app_path = app.__path__[0]
|
||||
else: # models.py module
|
||||
app_path = app.__file__
|
||||
return os.path.dirname(upath(app_path))
|
||||
|
||||
def get_app_path(self, app_label):
|
||||
return self._get_app_path(self.get_app(app_label))
|
||||
|
||||
def get_app_paths(self):
|
||||
"""
|
||||
Returns a list of paths to all installed apps.
|
||||
|
@ -165,10 +175,7 @@ class AppCache(object):
|
|||
|
||||
app_paths = []
|
||||
for app in self.get_apps():
|
||||
if hasattr(app, '__path__'): # models/__init__.py package
|
||||
app_paths.extend([upath(path) for path in app.__path__])
|
||||
else: # models.py module
|
||||
app_paths.append(upath(app.__file__))
|
||||
app_paths.append(self._get_app_path(app))
|
||||
return app_paths
|
||||
|
||||
def get_app(self, app_label, emptyOK=False):
|
||||
|
@ -321,6 +328,7 @@ cache = AppCache()
|
|||
# These methods were always module level, so are kept that way for backwards
|
||||
# compatibility.
|
||||
get_apps = cache.get_apps
|
||||
get_app_path = cache.get_app_path
|
||||
get_app_paths = cache.get_app_paths
|
||||
get_app = cache.get_app
|
||||
get_app_errors = cache.get_app_errors
|
||||
|
|
|
@ -414,6 +414,10 @@ these changes.
|
|||
|
||||
* ``django.utils.unittest`` will be removed.
|
||||
|
||||
* If models are organized in a package, Django will no longer look for
|
||||
:ref:`initial SQL data<initial-sql>` in ``myapp/models/sql/``. Move your
|
||||
custom SQL files to ``myapp/sql/``.
|
||||
|
||||
2.0
|
||||
---
|
||||
|
||||
|
|
|
@ -116,3 +116,12 @@ on all Python versions. Since ``unittest2`` became the standard library's
|
|||
:mod:`unittest` module in Python 2.7, and Django 1.7 drops support for older
|
||||
Python versions, this module isn't useful anymore. It has been deprecated. Use
|
||||
:mod:`unittest` instead.
|
||||
|
||||
Custom SQL location for models package
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Previously, if models were organized in a package (``myapp/models/``) rather
|
||||
than simply ``myapp/models.py``, Django would look for :ref:`initial SQL data
|
||||
<initial-sql>` in ``myapp/models/sql/``. This bug has been fixed so that Django
|
||||
will search ``myapp/sql/`` as documented. The old location will continue to
|
||||
work until Django 1.9.
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- Deprecated search path for custom SQL -- remove in Django 1.9
|
||||
INSERT INTO fixtures_model_package_book (name) VALUES ('My Deprecated Book');
|
|
@ -0,0 +1 @@
|
|||
INSERT INTO fixtures_model_package_book (name) VALUES ('My Book');
|
|
@ -5,6 +5,7 @@ import warnings
|
|||
from django.core import management
|
||||
from django.db import transaction
|
||||
from django.test import TestCase, TransactionTestCase
|
||||
from django.utils.six import StringIO
|
||||
|
||||
from .models import Article, Book
|
||||
|
||||
|
@ -110,3 +111,19 @@ class FixtureTestCase(TestCase):
|
|||
],
|
||||
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.assertTrue("INSERT INTO fixtures_model_package_book (name) "
|
||||
"VALUES ('My Book')" in output)
|
||||
# value from deprecated search path models/sql (remove in Django 1.9)
|
||||
self.assertTrue("Deprecated Book" in output)
|
||||
|
|
Loading…
Reference in New Issue