web/lib/django/core/management/commands/inspectdb.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
       
     1 import keyword
       
     2 from optparse import make_option
       
     3 
     1 from django.core.management.base import NoArgsCommand, CommandError
     4 from django.core.management.base import NoArgsCommand, CommandError
       
     5 from django.db import connections, DEFAULT_DB_ALIAS
     2 
     6 
     3 class Command(NoArgsCommand):
     7 class Command(NoArgsCommand):
     4     help = "Introspects the database tables in the given database and outputs a Django model module."
     8     help = "Introspects the database tables in the given database and outputs a Django model module."
     5 
     9 
       
    10     option_list = NoArgsCommand.option_list + (
       
    11         make_option('--database', action='store', dest='database',
       
    12             default=DEFAULT_DB_ALIAS, help='Nominates a database to '
       
    13                 'introspect.  Defaults to using the "default" database.'),
       
    14     )
       
    15 
     6     requires_model_validation = False
    16     requires_model_validation = False
       
    17 
       
    18     db_module = 'django.db'
     7 
    19 
     8     def handle_noargs(self, **options):
    20     def handle_noargs(self, **options):
     9         try:
    21         try:
    10             for line in self.handle_inspection():
    22             for line in self.handle_inspection(options):
    11                 print line
    23                 print line
    12         except NotImplementedError:
    24         except NotImplementedError:
    13             raise CommandError("Database inspection isn't supported for the currently selected database backend.")
    25             raise CommandError("Database inspection isn't supported for the currently selected database backend.")
    14 
    26 
    15     def handle_inspection(self):
    27     def handle_inspection(self, options):
    16         from django.db import connection
    28         connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
    17         import keyword
       
    18 
    29 
    19         table2model = lambda table_name: table_name.title().replace('_', '').replace(' ', '').replace('-', '')
    30         table2model = lambda table_name: table_name.title().replace('_', '').replace(' ', '').replace('-', '')
    20 
    31 
    21         cursor = connection.cursor()
    32         cursor = connection.cursor()
    22         yield "# This is an auto-generated Django model module."
    33         yield "# This is an auto-generated Django model module."
    26         yield "# Feel free to rename the models, but don't rename db_table values or field names."
    37         yield "# Feel free to rename the models, but don't rename db_table values or field names."
    27         yield "#"
    38         yield "#"
    28         yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
    39         yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
    29         yield "# into your database."
    40         yield "# into your database."
    30         yield ''
    41         yield ''
    31         yield 'from django.db import models'
    42         yield 'from %s import models' % self.db_module
    32         yield ''
    43         yield ''
    33         for table_name in connection.introspection.get_table_list(cursor):
    44         for table_name in connection.introspection.get_table_list(cursor):
    34             yield 'class %s(models.Model):' % table2model(table_name)
    45             yield 'class %s(models.Model):' % table2model(table_name)
    35             try:
    46             try:
    36                 relations = connection.introspection.get_relations(cursor, table_name)
    47                 relations = connection.introspection.get_relations(cursor, table_name)
    70                     if att_name.endswith('_id'):
    81                     if att_name.endswith('_id'):
    71                         att_name = att_name[:-3]
    82                         att_name = att_name[:-3]
    72                     else:
    83                     else:
    73                         extra_params['db_column'] = column_name
    84                         extra_params['db_column'] = column_name
    74                 else:
    85                 else:
    75                     try:
    86                     # Calling `get_field_type` to get the field type string and any
    76                         field_type = connection.introspection.get_field_type(row[1], row)
    87                     # additional paramters and notes.
    77                     except KeyError:
    88                     field_type, field_params, field_notes = self.get_field_type(connection, table_name, row)
    78                         field_type = 'TextField'
    89                     extra_params.update(field_params)
    79                         comment_notes.append('This field type is a guess.')
    90                     comment_notes.extend(field_notes)
    80 
       
    81                     # This is a hook for DATA_TYPES_REVERSE to return a tuple of
       
    82                     # (field_type, extra_params_dict).
       
    83                     if type(field_type) is tuple:
       
    84                         field_type, new_params = field_type
       
    85                         extra_params.update(new_params)
       
    86 
       
    87                     # Add max_length for all CharFields.
       
    88                     if field_type == 'CharField' and row[3]:
       
    89                         extra_params['max_length'] = row[3]
       
    90 
       
    91                     if field_type == 'DecimalField':
       
    92                         extra_params['max_digits'] = row[4]
       
    93                         extra_params['decimal_places'] = row[5]
       
    94 
    91 
    95                     # Add primary_key and unique, if necessary.
    92                     # Add primary_key and unique, if necessary.
    96                     if column_name in indexes:
    93                     if column_name in indexes:
    97                         if indexes[column_name]['primary_key']:
    94                         if indexes[column_name]['primary_key']:
    98                             extra_params['primary_key'] = True
    95                             extra_params['primary_key'] = True
   120                     field_desc += ', '.join(['%s=%r' % (k, v) for k, v in extra_params.items()])
   117                     field_desc += ', '.join(['%s=%r' % (k, v) for k, v in extra_params.items()])
   121                 field_desc += ')'
   118                 field_desc += ')'
   122                 if comment_notes:
   119                 if comment_notes:
   123                     field_desc += ' # ' + ' '.join(comment_notes)
   120                     field_desc += ' # ' + ' '.join(comment_notes)
   124                 yield '    %s' % field_desc
   121                 yield '    %s' % field_desc
   125             yield '    class Meta:'
   122             for meta_line in self.get_meta(table_name):
   126             yield '        db_table = %r' % table_name
   123                 yield meta_line
   127             yield ''
   124 
       
   125     def get_field_type(self, connection, table_name, row):
       
   126         """
       
   127         Given the database connection, the table name, and the cursor row
       
   128         description, this routine will return the given field type name, as
       
   129         well as any additional keyword parameters and notes for the field.
       
   130         """
       
   131         field_params = {}
       
   132         field_notes = []
       
   133 
       
   134         try:
       
   135             field_type = connection.introspection.get_field_type(row[1], row)
       
   136         except KeyError:
       
   137             field_type = 'TextField'
       
   138             field_notes.append('This field type is a guess.')
       
   139 
       
   140         # This is a hook for DATA_TYPES_REVERSE to return a tuple of
       
   141         # (field_type, field_params_dict).
       
   142         if type(field_type) is tuple:
       
   143             field_type, new_params = field_type
       
   144             field_params.update(new_params)
       
   145 
       
   146         # Add max_length for all CharFields.
       
   147         if field_type == 'CharField' and row[3]:
       
   148             field_params['max_length'] = row[3]
       
   149 
       
   150         if field_type == 'DecimalField':
       
   151             field_params['max_digits'] = row[4]
       
   152             field_params['decimal_places'] = row[5]
       
   153 
       
   154         return field_type, field_params, field_notes
       
   155 
       
   156     def get_meta(self, table_name):
       
   157         """
       
   158         Return a sequence comprising the lines of code necessary
       
   159         to construct the inner Meta class for the model corresponding
       
   160         to the given database table name.
       
   161         """
       
   162         return ['    class Meta:',
       
   163                 '        db_table = %r' % table_name,
       
   164                 '']