1
0
mirror of https://github.com/django/django.git synced 2025-06-13 23:49:13 +00:00

magic-removal:Management fixes. Everything works on app labels, and constraints generation is correct for mutually referential models.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@1716 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Robert Wittams 2005-12-17 15:39:22 +00:00
parent dbd3869610
commit bb874b690a
3 changed files with 119 additions and 80 deletions

View File

@ -44,16 +44,16 @@ EMPTY_CHANGELIST_VALUE = '(None)'
ADMIN_PREFIX = "/admin/" ADMIN_PREFIX = "/admin/"
def _get_mod_opts(app_label, module_name): #def _get_mod_opts(app_label, module_name):
"Helper function that returns a tuple of (module, opts), raising Http404 if necessary." # "Helper function that returns a tuple of (module, opts), raising Http404 if necessary."
try: # try:
mod = models.get_app(app_label) # mod = models.get_app(app_label)
except ImportError: # except ImportError:
raise Http404 # Invalid app or module name. Maybe it's not in INSTALLED_APPS. # raise Http404 # Invalid app or module name. Maybe it's not in INSTALLED_APPS.
opts = mod.Klass._meta # opts = mod.Klass._meta
if not opts.admin: # if not opts.admin:
raise Http404 # This object is valid but has no admin interface. # raise Http404 # This object is valid but has no admin interface.
return mod, opts # return mod, opts
def matches_app(mod, comps): def matches_app(mod, comps):
modcomps = mod.__name__.split('.')[:-1] #HACK: leave off 'models' modcomps = mod.__name__.split('.')[:-1] #HACK: leave off 'models'
@ -85,6 +85,7 @@ def find_model(mod, remaining):
raise Http404 raise Http404
def get_app_label(mod): def get_app_label(mod):
#HACK
modcomps = mod.__name__.split('.') modcomps = mod.__name__.split('.')
return modcomps[-2] return modcomps[-2]

View File

@ -63,16 +63,18 @@ def _is_valid_dir_name(s):
# type of field as the field to which it points. # type of field as the field to which it points.
get_rel_data_type = lambda f: (f.get_internal_type() == 'AutoField') and 'IntegerField' or f.get_internal_type() get_rel_data_type = lambda f: (f.get_internal_type() == 'AutoField') and 'IntegerField' or f.get_internal_type()
def get_sql_create(mod): def get_sql_create(app):
"Returns a list of the CREATE TABLE SQL statements for the given module." "Returns a list of the CREATE TABLE SQL statements for the given app."
from django.db import backend, get_creation_module, models from django.db import backend, get_creation_module, models
data_types = get_creation_module().DATA_TYPES data_types = get_creation_module().DATA_TYPES
final_output = [] final_output = []
opts_output = set() models_output = set()
pending_references = {} pending_references = {}
for klass in mod._MODELS: app_models = models.get_models(app)
for klass in app_models:
opts = klass._meta opts = klass._meta
table_output = [] table_output = []
for f in opts.fields: for f in opts.fields:
@ -92,14 +94,14 @@ def get_sql_create(mod):
if f.primary_key: if f.primary_key:
field_output.append('PRIMARY KEY') field_output.append('PRIMARY KEY')
if f.rel: if f.rel:
if f.rel.to in opts_output: if f.rel.to in models_output:
field_output.append('REFERENCES %s (%s)' % \ field_output.append('REFERENCES %s (%s)' % \
(backend.quote_name(f.rel.to._meta.db_table), (backend.quote_name(f.rel.to._meta.db_table),
backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column))) backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)))
else: else:
# We haven't yet created the table to which this field # We haven't yet created the table to which this field
# is related, so save it for later. # is related, so save it for later.
pr = pending_references.setdefault(f.rel.to._meta, []).append((opts, f)) pr = pending_references.setdefault(f.rel.to, []).append((klass, f))
table_output.append(' '.join(field_output)) table_output.append(' '.join(field_output))
if opts.order_with_respect_to: if opts.order_with_respect_to:
table_output.append('%s %s NULL' % (backend.quote_name('_order'), data_types['IntegerField'])) table_output.append('%s %s NULL' % (backend.quote_name('_order'), data_types['IntegerField']))
@ -115,8 +117,9 @@ def get_sql_create(mod):
# Take care of any ALTER TABLE statements to add constraints # Take care of any ALTER TABLE statements to add constraints
# after the fact. # after the fact.
if opts in pending_references: if klass in pending_references:
for rel_opts, f in pending_references[opts]: for rel_class, f in pending_references[klass]:
rel_opts = rel_class._meta
r_table = rel_opts.db_table r_table = rel_opts.db_table
r_col = f.column r_col = f.column
table = opts.db_table table = opts.db_table
@ -125,13 +128,13 @@ def get_sql_create(mod):
(backend.quote_name(r_table), (backend.quote_name(r_table),
backend.quote_name("%s_referencing_%s_%s" % (r_col, table, col)), backend.quote_name("%s_referencing_%s_%s" % (r_col, table, col)),
backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col)))
del pending_references[opts] del pending_references[klass]
# Keep track of the fact that we've created the table for this model. # Keep track of the fact that we've created the table for this model.
opts_output.add(opts) models_output.add(klass)
# Create the many-to-many join tables. # Create the many-to-many join tables.
for klass in mod._MODELS: for klass in app_models:
opts = klass._meta opts = klass._meta
for f in opts.many_to_many: for f in opts.many_to_many:
table_output = ['CREATE TABLE %s (' % backend.quote_name(f.get_m2m_db_table(opts))] table_output = ['CREATE TABLE %s (' % backend.quote_name(f.get_m2m_db_table(opts))]
@ -152,12 +155,12 @@ def get_sql_create(mod):
table_output.append(');') table_output.append(');')
final_output.append('\n'.join(table_output)) final_output.append('\n'.join(table_output))
return final_output return final_output
get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given model module name(s)." get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)."
get_sql_create.args = APP_ARGS get_sql_create.args = APP_ARGS
def get_sql_delete(mod): def get_sql_delete(app):
"Returns a list of the DROP TABLE SQL statements for the given module." "Returns a list of the DROP TABLE SQL statements for the given app."
from django.db import backend, connection from django.db import backend, connection, models
try: try:
cursor = connection.cursor() cursor = connection.cursor()
@ -183,7 +186,8 @@ def get_sql_delete(mod):
to_delete = set() to_delete = set()
references_to_delete = {} references_to_delete = {}
for klass in mod._MODELS: app_models = models.get_models(app)
for klass in app_models:
try: try:
if cursor is not None: if cursor is not None:
# Check whether the table exists. # Check whether the table exists.
@ -195,13 +199,11 @@ def get_sql_delete(mod):
opts = klass._meta opts = klass._meta
for f in opts.fields: for f in opts.fields:
if f.rel and f.rel.to not in to_delete: if f.rel and f.rel.to not in to_delete:
refs = references_to_delete.get(f.rel.to, []) references_to_delete.setdefault(f.rel.to, []).append( (klass, f) )
refs.append( (opts, f) )
references_to_delete[f.rel.to] = refs
to_delete.add(opts) to_delete.add(klass)
for klass in mod._MODELS: for klass in app_models:
try: try:
if cursor is not None: if cursor is not None:
# Check whether the table exists. # Check whether the table exists.
@ -211,18 +213,19 @@ def get_sql_delete(mod):
connection.rollback() connection.rollback()
else: else:
output.append("DROP TABLE %s;" % backend.quote_name(klass._meta.db_table)) output.append("DROP TABLE %s;" % backend.quote_name(klass._meta.db_table))
if references_to_delete.has_key(klass._meta): if references_to_delete.has_key(klass):
for opts, f in references_to_delete[klass._meta]: for rel_class, f in references_to_delete[klass]:
table = rel_class._meta.db_table
col = f.column col = f.column
table = opts.db_table r_table = klass._meta.db_table
r_table = f.rel.to._meta.db_table r_col = klass._meta.get_field(f.rel.field_name).column
r_col = f.rel.to.get_field(f.rel.field_name).column
output.append('ALTER TABLE %s DROP CONSTRAINT %s;' % \ output.append('ALTER TABLE %s DROP CONSTRAINT %s;' % \
(backend.quote_name(table), (backend.quote_name(table),
backend.quote_name("%s_referencing_%s_%s" % (col, r_table, r_col)))) backend.quote_name("%s_referencing_%s_%s" % (col, r_table, r_col))))
del references_to_delete[klass]
# Output DROP TABLE statements for many-to-many tables. # Output DROP TABLE statements for many-to-many tables.
for klass in mod._MODELS: for klass in app_models:
opts = klass._meta opts = klass._meta
for f in opts.many_to_many: for f in opts.many_to_many:
try: try:
@ -233,7 +236,7 @@ def get_sql_delete(mod):
else: else:
output.append("DROP TABLE %s;" % backend.quote_name(f.get_m2m_db_table(opts))) output.append("DROP TABLE %s;" % backend.quote_name(f.get_m2m_db_table(opts)))
app_label = mod._MODELS[0]._meta.app_label app_label = app_models[0]._meta.app_label
# Delete from packages, auth_permissions, content_types. # Delete from packages, auth_permissions, content_types.
output.append("DELETE FROM %s WHERE %s = '%s';" % \ output.append("DELETE FROM %s WHERE %s = '%s';" % \
@ -259,26 +262,31 @@ def get_sql_delete(mod):
connection.close() connection.close()
return output[::-1] # Reverse it, to deal with table dependencies. return output[::-1] # Reverse it, to deal with table dependencies.
get_sql_delete.help_doc = "Prints the DROP TABLE SQL statements for the given model module name(s)." get_sql_delete.help_doc = "Prints the DROP TABLE SQL statements for the given app name(s)."
get_sql_delete.args = APP_ARGS get_sql_delete.args = APP_ARGS
def get_sql_reset(mod): def get_sql_reset(app):
"Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module." "Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module."
return get_sql_delete(mod) + get_sql_all(mod) return get_sql_delete(app) + get_sql_all(app)
get_sql_reset.help_doc = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given model module name(s)." get_sql_reset.help_doc = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)."
get_sql_reset.args = APP_ARGS get_sql_reset.args = APP_ARGS
def get_sql_initial_data(mod): def get_sql_initial_data(app):
"Returns a list of the initial INSERT SQL statements for the given module." "Returns a list of the initial INSERT SQL statements for the given app."
from django.conf.settings import DATABASE_ENGINE from django.conf.settings import DATABASE_ENGINE
from django.db.models import get_models
output = [] output = []
app_label = mod._MODELS[0]._meta.app_label
app_models = get_models(app)
app_label = app_models[0]._meta.app_label
output.append(_get_packages_insert(app_label)) output.append(_get_packages_insert(app_label))
app_dir = os.path.normpath(os.path.join(os.path.dirname(mod.__file__), '..', 'sql')) app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
for klass in mod._MODELS:
for klass in app_models:
opts = klass._meta opts = klass._meta
# Add custom SQL, if it's available. # Add custom SQL, if it's available.
# FIXME: THis probably needs changing
sql_files = [os.path.join(app_dir, opts.module_name + '.' + DATABASE_ENGINE + '.sql'), sql_files = [os.path.join(app_dir, opts.module_name + '.' + DATABASE_ENGINE + '.sql'),
os.path.join(app_dir, opts.module_name + '.sql')] os.path.join(app_dir, opts.module_name + '.sql')]
for sql_file in sql_files: for sql_file in sql_files:
@ -293,14 +301,15 @@ def get_sql_initial_data(mod):
for codename, name in _get_all_permissions(opts): for codename, name in _get_all_permissions(opts):
output.append(_get_permission_insert(name, codename, opts)) output.append(_get_permission_insert(name, codename, opts))
return output return output
get_sql_initial_data.help_doc = "Prints the initial INSERT SQL statements for the given model module name(s)." get_sql_initial_data.help_doc = "Prints the initial INSERT SQL statements for the given app name(s)."
get_sql_initial_data.args = APP_ARGS get_sql_initial_data.args = APP_ARGS
def get_sql_sequence_reset(mod):
"Returns a list of the SQL statements to reset PostgreSQL sequences for the given module." def get_sql_sequence_reset(app):
"Returns a list of the SQL statements to reset PostgreSQL sequences for the given app."
from django.db import backend, models from django.db import backend, models
output = [] output = []
for klass in mod._MODELS: for klass in models.get_models(app):
for f in klass._meta.fields: for f in klass._meta.fields:
if isinstance(f, models.AutoField): if isinstance(f, models.AutoField):
output.append("SELECT setval('%s_%s_seq', (SELECT max(%s) FROM %s));" % \ output.append("SELECT setval('%s_%s_seq', (SELECT max(%s) FROM %s));" % \
@ -310,14 +319,15 @@ def get_sql_sequence_reset(mod):
output.append("SELECT setval('%s_id_seq', (SELECT max(%s) FROM %s));" % \ output.append("SELECT setval('%s_id_seq', (SELECT max(%s) FROM %s));" % \
(f.get_m2m_db_table(klass._meta), backend.quote_name('id'), f.get_m2m_db_table(klass._meta))) (f.get_m2m_db_table(klass._meta), backend.quote_name('id'), f.get_m2m_db_table(klass._meta)))
return output return output
get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting PostgreSQL sequences for the given model module name(s)." get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting PostgreSQL sequences for the given app name(s)."
get_sql_sequence_reset.args = APP_ARGS get_sql_sequence_reset.args = APP_ARGS
def get_sql_indexes(mod): def get_sql_indexes(app):
"Returns a list of the CREATE INDEX SQL statements for the given module." "Returns a list of the CREATE INDEX SQL statements for the given app."
from django.db import backend from django.db import backend, models
output = [] output = []
for klass in mod._MODELS:
for klass in models.get_models(app):
for f in klass._meta.fields: for f in klass._meta.fields:
if f.db_index: if f.db_index:
unique = f.unique and "UNIQUE " or "" unique = f.unique and "UNIQUE " or ""
@ -328,9 +338,9 @@ def get_sql_indexes(mod):
get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)." get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
get_sql_indexes.args = APP_ARGS get_sql_indexes.args = APP_ARGS
def get_sql_all(mod): def get_sql_all(app):
"Returns a list of CREATE TABLE SQL and initial-data insert for the given module." "Returns a list of CREATE TABLE SQL and initial-data insert for the given app."
return get_sql_create(mod) + get_sql_initial_data(mod) return get_sql_create(app) + get_sql_initial_data(app)
get_sql_all.help_doc = "Prints the CREATE TABLE and initial-data SQL statements for the given model module name(s)." get_sql_all.help_doc = "Prints the CREATE TABLE and initial-data SQL statements for the given model module name(s)."
get_sql_all.args = APP_ARGS get_sql_all.args = APP_ARGS
@ -343,11 +353,12 @@ def has_no_records(cursor):
return cursor.fetchone() is None return cursor.fetchone() is None
return cursor.rowcount < 1 return cursor.rowcount < 1
def database_check(mod): def database_check(app):
"Checks that everything is properly installed in the database for the given module." "Checks that everything is properly installed in the database for the given module."
from django.db import backend, connection from django.db import backend, connection, models
cursor = connection.cursor() cursor = connection.cursor()
app_label = mod._MODELS[0]._meta.app_label app_modules = models.get_models(app)
app_label = app_modules[0]._meta.app_label
# Check that the package exists in the database. # Check that the package exists in the database.
cursor.execute("SELECT 1 FROM %s WHERE %s = %%s" % \ cursor.execute("SELECT 1 FROM %s WHERE %s = %%s" % \
@ -359,7 +370,7 @@ def database_check(mod):
# Check that the permissions and content types are in the database. # Check that the permissions and content types are in the database.
perms_seen = {} perms_seen = {}
contenttypes_seen = {} contenttypes_seen = {}
for klass in mod._MODELS: for klass in app_models:
opts = klass._meta opts = klass._meta
perms = _get_all_permissions(opts) perms = _get_all_permissions(opts)
perms_seen.update(dict(perms)) perms_seen.update(dict(perms))
@ -408,11 +419,13 @@ def database_check(mod):
database_check.help_doc = "Checks that everything is installed in the database for the given model module name(s) and prints SQL statements if needed." database_check.help_doc = "Checks that everything is installed in the database for the given model module name(s) and prints SQL statements if needed."
database_check.args = APP_ARGS database_check.args = APP_ARGS
def get_admin_index(mod): def get_admin_index(app):
"Returns admin-index template snippet (in list form) for the given module." "Returns admin-index template snippet (in list form) for the given app."
from django.utils.text import capfirst from django.utils.text import capfirst
from django.db.models import get_models
output = [] output = []
app_label = mod._MODELS[0]._meta.app_label app_models = get_models(app)
app_label = app_models[0]._meta.app_label
output.append('{%% if perms.%s %%}' % app_label) output.append('{%% if perms.%s %%}' % app_label)
output.append('<div class="module"><h2>%s</h2><table>' % app_label.title()) output.append('<div class="module"><h2>%s</h2><table>' % app_label.title())
for klass in mod._MODELS: for klass in mod._MODELS:
@ -427,7 +440,7 @@ def get_admin_index(mod):
output.append('</table></div>') output.append('</table></div>')
output.append('{% endif %}') output.append('{% endif %}')
return output return output
get_admin_index.help_doc = "Prints the admin-index template snippet for the given model module name(s)." get_admin_index.help_doc = "Prints the admin-index template snippet for the given app name(s)."
get_admin_index.args = APP_ARGS get_admin_index.args = APP_ARGS
def init(): def init():
@ -454,12 +467,13 @@ def init():
connection.commit() connection.commit()
init.args = '' init.args = ''
def install(mod): def install(app):
"Executes the equivalent of 'get_sql_all' in the current database." "Executes the equivalent of 'get_sql_all' in the current database."
from django.db import connection from django.db import connection
from cStringIO import StringIO from cStringIO import StringIO
mod_name = mod.__name__[mod.__name__.rindex('.')+1:] app_name = app.__name__[app.__name__.rindex('.')+1:]
app_label = app_name.split('.')[-1]
# First, try validating the models. # First, try validating the models.
s = StringIO() s = StringIO()
num_errors = get_validation_errors(s) num_errors = get_validation_errors(s)
@ -468,7 +482,7 @@ def install(mod):
s.seek(0) s.seek(0)
sys.stderr.write(s.read()) sys.stderr.write(s.read())
sys.exit(1) sys.exit(1)
sql_list = get_sql_all(mod) sql_list = get_sql_all(app)
try: try:
cursor = connection.cursor() cursor = connection.cursor()
@ -481,20 +495,23 @@ def install(mod):
* The SQL was invalid. * The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlall %s'. That's the SQL this command wasn't able to run. Hint: Look at the output of 'django-admin.py sqlall %s'. That's the SQL this command wasn't able to run.
The full error: %s\n""" % \ The full error: %s\n""" % \
(mod_name, mod_name, e)) (app_name, app_label, e))
connection.rollback() connection.rollback()
sys.exit(1) sys.exit(1)
connection.commit() connection.commit()
install.help_doc = "Executes ``sqlall`` for the given model module name(s) in the current database." install.help_doc = "Executes ``sqlall`` for the given app(s) in the current database."
install.args = APP_ARGS install.args = APP_ARGS
def installperms(mod): def installperms(app):
"Installs any permissions for the given model, if needed." "Installs any permissions for the given app, if needed."
from django.models.auth import Permission from django.models.auth import Permission
from django.models.core import Package from django.models.core import Package
from django.db.models import get_models
num_added = 0 num_added = 0
package = Package.objects.get_object(pk=mod._MODELS[0]._meta.app_label) app_models = get_models(app)
for klass in mod._MODELS: app_label = app_models[0]._meta.app_label
package = Package.objects.get_object(pk=app_label)
for klass in app_models:
opts = klass._meta opts = klass._meta
for codename, name in _get_all_permissions(opts): for codename, name in _get_all_permissions(opts):
try: try:

View File

@ -14,10 +14,11 @@ from django.db.models.base import Model
from django.db.models.fields import * from django.db.models.fields import *
from django.db.models.fields.related import * from django.db.models.fields.related import *
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
from django.db.models.exceptions import FieldDoesNotExist, BadKeywordArguments from django.db.models.exceptions import FieldDoesNotExist, BadKeywordArguments
from django.db.models.signals import Signals from django.db.models.signals import Signals
# Admin stages. # Admin stages.
ADD, CHANGE, BOTH = 1, 2, 3 ADD, CHANGE, BOTH = 1, 2, 3
@ -25,8 +26,28 @@ ADD, CHANGE, BOTH = 1, 2, 3
#def get_module(app_label, module_name): #def get_module(app_label, module_name):
# return __import__('%s.%s.%s' % (MODEL_PREFIX, app_label, module_name), '', '', ['']) # return __import__('%s.%s.%s' % (MODEL_PREFIX, app_label, module_name), '', '', [''])
#def get_app(app_label): def get_models(app):
# return __import__('%s.%s' % (MODEL_PREFIX, app_label), '', '', ['']) models = []
get_models_helper(app, models)
return models
def get_models_helper(mod, seen_models):
if hasattr(mod, '_MODELS'):
seen_models.extend(mod._MODELS)
if hasattr(mod, '__all__'):
for name in mod.__all__:
sub_mod = __import__("%s.%s" % (mod.__name__, name), '','',[''])
get_models_helper(sub_mod, seen_models)
def get_app(app_label):
for app_name in settings.INSTALLED_APPS:
comps = app_name.split('.')
if app_label == comps[-1]:
app_models = __import__('%s.models' % app_name , '','',[''])
return app_models
raise ImproperlyConfigured, "App with label %s could not be found" % app_name
class LazyDate: class LazyDate:
""" """