summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
Diffstat (limited to 'django')
-rw-r--r--django/core/management/commands/inspectdb.py28
-rw-r--r--django/db/backends/postgresql/features.py1
-rw-r--r--django/db/backends/postgresql/introspection.py15
3 files changed, 27 insertions, 17 deletions
diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py
index cbebd6f60c..5cdd52fccf 100644
--- a/django/core/management/commands/inspectdb.py
+++ b/django/core/management/commands/inspectdb.py
@@ -23,6 +23,9 @@ class Command(BaseCommand):
help='Nominates a database to introspect. Defaults to using the "default" database.',
)
parser.add_argument(
+ '--include-partitions', action='store_true', help='Also output models for partition tables.',
+ )
+ parser.add_argument(
'--include-views', action='store_true', help='Also output models for database views.',
)
@@ -55,12 +58,15 @@ class Command(BaseCommand):
yield 'from %s import models' % self.db_module
known_models = []
table_info = connection.introspection.get_table_list(cursor)
- tables_to_introspect = (
- options['table'] or
- sorted(info.name for info in table_info if options['include_views'] or info.type == 't')
- )
- for table_name in tables_to_introspect:
+ # Determine types of tables and/or views to be introspected.
+ types = {'t'}
+ if options['include_partitions']:
+ types.add('p')
+ if options['include_views']:
+ types.add('v')
+
+ for table_name in (options['table'] or sorted(info.name for info in table_info if info.type in types)):
if table_name_filter is not None and callable(table_name_filter):
if not table_name_filter(table_name):
continue
@@ -160,7 +166,8 @@ class Command(BaseCommand):
field_desc += ' # ' + ' '.join(comment_notes)
yield ' %s' % field_desc
is_view = any(info.name == table_name and info.type == 'v' for info in table_info)
- for meta_line in self.get_meta(table_name, constraints, column_to_field_name, is_view):
+ is_partition = any(info.name == table_name and info.type == 'p' for info in table_info)
+ for meta_line in self.get_meta(table_name, constraints, column_to_field_name, is_view, is_partition):
yield meta_line
def normalize_col_name(self, col_name, used_column_names, is_relation):
@@ -257,7 +264,7 @@ class Command(BaseCommand):
return field_type, field_params, field_notes
- def get_meta(self, table_name, constraints, column_to_field_name, is_view):
+ def get_meta(self, table_name, constraints, column_to_field_name, is_view, is_partition):
"""
Return a sequence comprising the lines of code necessary
to construct the inner Meta class for the model corresponding
@@ -273,7 +280,12 @@ class Command(BaseCommand):
columns = [x for x in columns if x is not None]
if len(columns) > 1:
unique_together.append(str(tuple(column_to_field_name[c] for c in columns)))
- managed_comment = " # Created from a view. Don't remove." if is_view else ""
+ if is_view:
+ managed_comment = " # Created from a view. Don't remove."
+ elif is_partition:
+ managed_comment = " # Created from a partition. Don't remove."
+ else:
+ managed_comment = ''
meta = ['']
if has_unsupported_constraint:
meta.append(' # A unique constraint could not be introspected.')
diff --git a/django/db/backends/postgresql/features.py b/django/db/backends/postgresql/features.py
index 3f43abf9d5..89ff06fdf5 100644
--- a/django/db/backends/postgresql/features.py
+++ b/django/db/backends/postgresql/features.py
@@ -73,3 +73,4 @@ class DatabaseFeatures(BaseDatabaseFeatures):
has_gin_pending_list_limit = property(operator.attrgetter('is_postgresql_9_5'))
supports_ignore_conflicts = property(operator.attrgetter('is_postgresql_9_5'))
has_phraseto_tsquery = property(operator.attrgetter('is_postgresql_9_6'))
+ supports_table_partitions = property(operator.attrgetter('is_postgresql_10'))
diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py
index 85538262cb..3ce88ccfbf 100644
--- a/django/db/backends/postgresql/introspection.py
+++ b/django/db/backends/postgresql/introspection.py
@@ -42,18 +42,15 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
def get_table_list(self, cursor):
"""Return a list of table and view names in the current database."""
cursor.execute("""
- SELECT c.relname, c.relkind
+ SELECT c.relname,
+ CASE WHEN {} THEN 'p' WHEN c.relkind IN ('m', 'v') THEN 'v' ELSE 't' END
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
- WHERE c.relkind IN ('f', 'm', 'r', 'v')
+ WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v')
AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
AND pg_catalog.pg_table_is_visible(c.oid)
- """)
- mapping = {'f': 't', 'm': 'v', 'r': 't', 'v': 'v'}
- return [
- TableInfo(row[0], mapping[row[1]])
- for row in cursor.fetchall() if row[0] not in self.ignored_tables
- ]
+ """.format('c.relispartition' if self.connection.features.supports_table_partitions else 'FALSE'))
+ return [TableInfo(*row) for row in cursor.fetchall() if row[0] not in self.ignored_tables]
def get_table_description(self, cursor, table_name):
"""
@@ -73,7 +70,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
JOIN pg_type t ON a.atttypid = t.oid
JOIN pg_class c ON a.attrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
- WHERE c.relkind IN ('f', 'm', 'r', 'v')
+ WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v')
AND c.relname = %s
AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
AND pg_catalog.pg_table_is_visible(c.oid)