Skip to content

Commit

Permalink
Fixed #14305 -- Switched inspectdb to create unmanaged models.
Browse files Browse the repository at this point in the history
Thanks Ian Kelly for the report and initial patch.
  • Loading branch information
ramiro committed Feb 3, 2013
1 parent c9c40bc commit 08dc90b
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 2 deletions.
6 changes: 4 additions & 2 deletions django/core/management/commands/inspectdb.py
Expand Up @@ -40,8 +40,9 @@ def handle_inspection(self, options):
cursor = connection.cursor() cursor = connection.cursor()
yield "# This is an auto-generated Django model module." yield "# This is an auto-generated Django model module."
yield "# You'll have to do the following manually to clean this up:" yield "# You'll have to do the following manually to clean this up:"
yield "# * Rearrange models' order" yield "# * Rearrange models' order"
yield "# * Make sure each model has one field with primary_key=True" yield "# * Make sure each model has one field with primary_key=True"
yield "# * Remove `managed = False` lines for those models you wish to give write DB access"
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 "#"
yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'" yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
Expand Down Expand Up @@ -224,5 +225,6 @@ def get_meta(self, table_name):
to the given database table name. to the given database table name.
""" """
return [" class Meta:", return [" class Meta:",
" managed = False",
" db_table = '%s'" % table_name, " db_table = '%s'" % table_name,
""] ""]
29 changes: 29 additions & 0 deletions docs/howto/legacy-databases.txt
Expand Up @@ -49,6 +49,35 @@ Once you've cleaned up your models, name the file ``models.py`` and put it in
the Python package that holds your app. Then add the app to your the Python package that holds your app. Then add the app to your
:setting:`INSTALLED_APPS` setting. :setting:`INSTALLED_APPS` setting.


If your plan is that your Django application(s) modify data (i.e. edit, remove
records and create new ones) in the existing database tables corresponding to
any of the introspected models then one of the manual review and edit steps
you need to perform on the resulting ``models.py`` file is to change the
Python declaration of each one of these models to specify it is a
:attr:`managed <django.db.models.Options.managed>` one. For example, consider
this generated model definition:

.. parsed-literal::

class Person(models.Model):
id = models.IntegerField(primary_key=True)
first_name = models.ChaField(max_length=70)
class Meta:
**managed = False**
db_table = 'CENSUS_PERSONS'

If you wanted to modify existing data on your ``CENSUS_PERSONS`` SQL table
with Django you'd need to change the ``managed`` option highlighted above to
``True`` (or simply remove it to let it because ``True`` is its default value).

This servers as an explicit opt-in to give your nascent Django project write
access to your precious data on a model by model basis.

.. versionchanged:: 1.6

The behavior by which introspected models are created as unmanaged ones is new
in Django 1.6.

Install the core Django tables Install the core Django tables
============================== ==============================


Expand Down
15 changes: 15 additions & 0 deletions docs/ref/django-admin.txt
Expand Up @@ -288,9 +288,24 @@ needed.
``inspectdb`` works with PostgreSQL, MySQL and SQLite. Foreign-key detection ``inspectdb`` works with PostgreSQL, MySQL and SQLite. Foreign-key detection
only works in PostgreSQL and with certain types of MySQL tables. only works in PostgreSQL and with certain types of MySQL tables.


If your plan is that your Django application(s) modify data (i.e. edit, remove
records and create new ones) in the existing database tables corresponding to
any of the introspected models then one of the manual review and edit steps
you need to perform on the resulting ``models.py`` file is to change the
Python declaration of each one of these models to specify it is a
:attr:`managed <django.db.models.Options.managed>` one.

This servers as an explicit opt-in to give your nascent Django project write
access to your precious data on a model by model basis.

The :djadminopt:`--database` option may be used to specify the The :djadminopt:`--database` option may be used to specify the
database to introspect. database to introspect.


.. versionchanged:: 1.6

The behavior by which introspected models are created as unmanaged ones is new
in Django 1.6.

loaddata <fixture fixture ...> loaddata <fixture fixture ...>
------------------------------ ------------------------------


Expand Down
10 changes: 10 additions & 0 deletions tests/regressiontests/inspectdb/tests.py
Expand Up @@ -140,3 +140,13 @@ def test_special_column_name_introspection(self):
self.assertIn("field_field_0 = models.IntegerField(db_column='%s__')" % base_name, output) self.assertIn("field_field_0 = models.IntegerField(db_column='%s__')" % base_name, output)
self.assertIn("field_field_1 = models.IntegerField(db_column='__field')", output) self.assertIn("field_field_1 = models.IntegerField(db_column='__field')", output)
self.assertIn("prc_x = models.IntegerField(db_column='prc(%) x')", output) self.assertIn("prc_x = models.IntegerField(db_column='prc(%) x')", output)

def test_managed_models(self):
"""Test that by default the command generates models with `Meta.managed = False` (#14305)"""
out = StringIO()
call_command('inspectdb',
table_name_filter=lambda tn:tn.startswith('inspectdb_columntypes'),
stdout=out)
output = out.getvalue()
self.longMessage = False
self.assertIn(" managed = False", output, msg='inspectdb should generate unmanaged models.')

0 comments on commit 08dc90b

Please sign in to comment.