Ticket #4528: pre_syncdb_updated.patch

File pre_syncdb_updated.patch, 8.5 KB (added by Silver_Ghost, 13 years ago)

Updated patch with tests.

  • django/core/management/commands/flush.py

    diff -r 9c6c09152c06 django/core/management/commands/flush.py
    a b  
    55from django.core.management import call_command
    66from django.core.management.base import NoArgsCommand, CommandError
    77from django.core.management.color import no_style
    8 from django.core.management.sql import sql_flush, emit_post_sync_signal
     8from django.core.management.sql import sql_flush, emit_post_sync_signal, emit_pre_sync_signal
    99from django.utils.importlib import import_module
    1010
    1111
     
    5151            confirm = 'yes'
    5252
    5353        if confirm == 'yes':
     54            emit_pre_sync_signal(verbosity, interactive, db)
    5455            try:
    5556                cursor = connection.cursor()
    5657                for sql in sql_list:
  • django/core/management/commands/syncdb.py

    diff -r 9c6c09152c06 django/core/management/commands/syncdb.py
    a b  
    55from django.conf import settings
    66from django.core.management.base import NoArgsCommand
    77from django.core.management.color import no_style
    8 from django.core.management.sql import custom_sql_for_model, emit_post_sync_signal
     8from django.core.management.sql import custom_sql_for_model, emit_post_sync_signal, emit_pre_sync_signal
    99from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
    1010from django.utils.datastructures import SortedDict
    1111from django.utils.importlib import import_module
     
    5454
    5555        db = options.get('database')
    5656        connection = connections[db]
     57        emit_pre_sync_signal(verbosity, interactive, db)
    5758        cursor = connection.cursor()
    5859
    5960        # Get a list of already installed *models* so that references work right.
  • django/core/management/sql.py

    diff -r 9c6c09152c06 django/core/management/sql.py
    a b  
    178178    return output
    179179
    180180
     181def emit_pre_sync_signal(verbosity, interactive, db):
     182    # Emit the pre_sync signal for every application.
     183    for app in models.get_apps():
     184        app_name = app.__name__.split('.')[-2]
     185        if verbosity >= 2:
     186            print "Running pre-sync handlers for application", app_name
     187        models.signals.pre_syncdb.send(sender=app, app=app,
     188                                       verbosity=verbosity,
     189                                       interactive=interactive,
     190                                       db=db)
     191
     192
    181193def emit_post_sync_signal(created_models, verbosity, interactive, db):
    182194    # Emit the post_sync signal for every application.
    183195    for app in models.get_apps():
     
    187199        models.signals.post_syncdb.send(sender=app, app=app,
    188200            created_models=created_models, verbosity=verbosity,
    189201            interactive=interactive, db=db)
     202
  • django/db/models/signals.py

    diff -r 9c6c09152c06 django/db/models/signals.py
    a b  
    1111pre_delete = Signal(providing_args=["instance", "using"])
    1212post_delete = Signal(providing_args=["instance", "using"])
    1313
     14pre_syncdb = Signal(providing_args=["app", "verbosity", "interactive", "db"])
    1415post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"])
    1516
    1617m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"])
  • docs/ref/signals.txt

    diff -r 9c6c09152c06 docs/ref/signals.txt
    a b  
    352352
    353353Signals sent by :doc:`django-admin </ref/django-admin>`.
    354354
     355pre_syncdb
     356----------
     357
     358.. data:: django.db.models.signals.pre_syncdb
     359   :module:
     360
     361Sent by the :djadmin:`syncdb` command before it starts to install an application, and the :djadmin:`flush` command.
     362
     363Arguments sent with this signal:
     364
     365``sender``
     366    The ``models`` module that was just installed. That is, if
     367    :djadmin:`syncdb` just installed an app called ``"foo.bar.myapp"``,
     368    ``sender`` will be the ``foo.bar.myapp.models`` module.
     369
     370``app``
     371    Same as ``sender``.
     372
     373``db``
     374    The alias of database on which a command will operate.
     375
     376``verbosity``
     377    Indicates how much information manage.py is printing on screen. See
     378    the :djadminopt:`--verbosity` flag for details.
     379
     380    Functions which listen for :data:`pre_syncdb` should adjust what they
     381    output to the screen based on the value of this argument.
     382
     383``interactive``
     384    If ``interactive`` is ``True``, it's safe to prompt the user to input
     385    things on the command line. If ``interactive`` is ``False``, functions
     386    which listen for this signal should not try to prompt for anything.
     387
     388    For example, the :mod:`django.contrib.auth` app only prompts to create a
     389    superuser when ``interactive`` is ``True``.
     390
    355391post_syncdb
    356392-----------
    357393
  • new file tests/regressiontests/syncdb/__init__.py

    diff -r 9c6c09152c06 tests/regressiontests/syncdb/__init__.py
    - +  
     1
  • new file tests/regressiontests/syncdb/models.py

    diff -r 9c6c09152c06 tests/regressiontests/syncdb/models.py
    - +  
     1from django.db import models
     2
     3
     4class Author(models.Model):
     5    name = models.CharField(max_length=100)
     6
     7    class Meta:
     8        ordering = ['name']
     9
     10    def __unicode__(self):
     11        return self.name
  • new file tests/regressiontests/syncdb/tests.py

    diff -r 9c6c09152c06 tests/regressiontests/syncdb/tests.py
    - +  
     1from django.db import connections
     2from django.db.models import signals
     3from django.test import TestCase
     4from django.core import management
     5
     6import models
     7
     8
     9PRE_SYNCDB_ARGS = ['app', 'verbosity', 'interactive', 'db']
     10SYNCDB_DATABASE = 'default'
     11SYNCDB_VERBOSITY = 1
     12SYNCDB_INTERACTIVE = False
     13
     14
     15class PreSyncdbReceiver(object):
     16    def __init__(self):
     17        self.call_counter = 0
     18        self.call_args = None
     19
     20    def __call__(self, signal, sender, **kwargs):
     21        self.call_counter = self.call_counter + 1
     22        self.call_args = kwargs
     23
     24
     25class OneTimeReceiver(object):
     26    """
     27    Special receiver for handle the fact that test runner calls syncdb for
     28    several databases and several times for some of them.
     29    """
     30   
     31    def __init__(self):
     32        self.call_counter = 0
     33        self.call_args = None
     34        self.tables = None  # list of tables at the time of the call
     35
     36    def __call__(self, signal, sender, **kwargs):
     37        # Although test runner calls syncdb for several databases,
     38        # testing for only one of them is quite sufficient.
     39        if kwargs['db'] == SYNCDB_DATABASE:
     40            self.call_counter = self.call_counter + 1
     41            self.call_args = kwargs
     42            connection = connections[SYNCDB_DATABASE]
     43            self.tables = connection.introspection.table_names()
     44            # we need to test only one call of syncdb
     45            signals.pre_syncdb.disconnect(pre_syncdb_receiver, sender=models)
     46
     47
     48# We connect receiver here and not in unit test code because we need to
     49# connect receiver before test runner creates database.  That is, sequence of
     50# actions would be:
     51#   
     52#   1. Test runner imports this module.
     53#   2. We connect receiver.
     54#   3. Test runner calls syncdb for create default database.
     55#   4. Test runner execute our unit test code.
     56pre_syncdb_receiver = OneTimeReceiver()
     57signals.pre_syncdb.connect(pre_syncdb_receiver, sender=models)
     58
     59
     60class SyncdbSignalTests(TestCase):
     61    def test_pre_syncdb_call_time(self):
     62        self.assertEqual(pre_syncdb_receiver.call_counter, 1)
     63        self.assertFalse(pre_syncdb_receiver.tables)
     64
     65    def test_pre_syncdb_args(self):
     66        r = PreSyncdbReceiver()
     67        signals.pre_syncdb.connect(r, sender=models)
     68        management.call_command('syncdb', database=SYNCDB_DATABASE,
     69            verbosity=SYNCDB_VERBOSITY, interactive=SYNCDB_INTERACTIVE)
     70       
     71        args = r.call_args
     72        self.assertEqual(r.call_counter, 1)
     73        self.assertItemsEqual(args, PRE_SYNCDB_ARGS)
     74        self.assertEqual(args['app'], models)
     75        self.assertEqual(args['verbosity'], SYNCDB_VERBOSITY)
     76        self.assertEqual(args['interactive'], SYNCDB_INTERACTIVE)
     77        self.assertEqual(args['db'], 'default')
Back to Top