Django

Code

Ticket #2333: fixtures.diff

File fixtures.diff, 34.9 kB (added by russellm, 2 years ago)

Phase 3, version 1 of the testing framework - fixtures

  • django/test/testcases.py

    old new  
    11import re, doctest, unittest 
    22from django.db import transaction 
     3from django.core import management 
     4from django.db.models import get_apps 
    35     
    46normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s) 
    57 
     
    1921    def __init__(self, *args, **kwargs): 
    2022        doctest.DocTestRunner.__init__(self, *args, **kwargs) 
    2123        self.optionflags = doctest.ELLIPSIS 
     24        management.flush(verbosity=0, interactive=False) 
    2225         
    2326    def report_unexpected_exception(self, out, test, example, exc_info): 
    2427        doctest.DocTestRunner.report_unexpected_exception(self,out,test,example,exc_info) 
     
    2831        from django.db import transaction 
    2932        transaction.rollback_unless_managed() 
    3033 
     34class TestCase(unittest.TestCase):     
     35    def install_fixtures(self): 
     36        """If the Test Case class has a 'fixtures' member, clear the database and 
     37        install the named fixtures at the start of each test. 
     38         
     39        """ 
     40        management.flush(verbosity=0, interactive=False) 
     41        if hasattr(self, 'fixtures'): 
     42            for format,fixtures in self.fixtures.items(): 
     43                management.install_fixtures(fixtures, format=format, verbosity=0) 
     44 
     45    def run(self, result=None): 
     46        """Wrapper around default run method so that user-defined Test Cases  
     47        automatically call install_fixtures without having to include a call to  
     48        super(). 
     49         
     50        """ 
     51        self.install_fixtures() 
     52        super(TestCase, self).run(result) 
  • django/test/__init__.py

    old new  
     1""" 
     2Django Unit Test and Doctest framework. 
     3""" 
     4 
     5from django.test.client import Client 
     6from django.test.testcases import TestCase 
  • django/conf/global_settings.py

    old new  
    315315# The name of the database to use for testing purposes. 
    316316# If None, a name of 'test_' + DATABASE_NAME will be assumed 
    317317TEST_DATABASE_NAME = None 
     318 
     319############ 
     320# FIXTURES # 
     321############ 
     322 
     323# The list of directories to search for fixtures 
     324FIXTURE_DIRS = () 
  • django/db/backends/ado_mssql/base.py

    old new  
    134134def get_pk_default_value(): 
    135135    return "DEFAULT" 
    136136 
     137def get_sql_flush(sql_styler, full_table_list): 
     138    """Return a list of SQL statements required to remove all data from 
     139    all tables in the database (without actually removing the tables 
     140    themselves) and put the database in an empty 'initial' state 
     141    """ 
     142    # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements 
     143    # TODO - SQL not actually tested against ADO MSSQL yet! 
     144    # TODO - autoincrement indices reset required? See other get_sql_flush() implementations 
     145    sql_list = ['%s %s;' % \ 
     146                (sql_styler.SQL_KEYWORD('TRUNCATE'), 
     147                 sql_styler.SQL_FIELD(quote_name(table)) 
     148                 )  for table in full_table_list] 
     149 
    137150OPERATOR_MAPPING = { 
    138151    'exact': '= %s', 
    139152    'iexact': 'LIKE %s', 
  • django/db/backends/postgresql/base.py

    old new  
    112112def get_pk_default_value(): 
    113113    return "DEFAULT" 
    114114 
     115def get_sql_flush(style, tables, sequences): 
     116    """Return a list of SQL statements required to remove all data from 
     117    all tables in the database (without actually removing the tables 
     118    themselves) and put the database in an empty 'initial' state 
     119     
     120    """ 
     121    # Postgres can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to 
     122    # truncate tables referenced by a foreign key in any other table. The result is a 
     123    # single SQL TRUNCATE statement. 
     124    if tables: 
     125        sql = ['%s %s;' % \ 
     126            (style.SQL_KEYWORD('TRUNCATE'), 
     127             style.SQL_FIELD(', '.join(quote_name(table) for table in tables)) 
     128        )] 
     129     
     130        # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements 
     131        # to reset sequence indices 
     132        for sequence_info in sequences: 
     133            table_name = sequence_info['table'] 
     134            column_name = sequence_info['column'] 
     135            if column_name and len(column_name)>0: 
     136                # sequence name in this case will be <table>_<column>_seq 
     137                sql.append("%s %s %s %s %s %s;" % \ 
     138                    (style.SQL_KEYWORD('ALTER'), 
     139                    style.SQL_KEYWORD('SEQUENCE'), 
     140                    style.SQL_FIELD('%s_%s_seq' % (table_name, column_name)), 
     141                    style.SQL_KEYWORD('RESTART'), 
     142                    style.SQL_KEYWORD('WITH'), 
     143                    style.SQL_FIELD('1') 
     144                    ) 
     145                ) 
     146            else: 
     147                # sequence name in this case will be <table>_id_seq 
     148                sql.append("%s %s %s %s %s %s;" % \ 
     149                    (style.SQL_KEYWORD('ALTER'), 
     150                     style.SQL_KEYWORD('SEQUENCE'), 
     151                     style.SQL_FIELD('%s_id_seq' % table_name), 
     152                     style.SQL_KEYWORD('RESTART'), 
     153                     style.SQL_KEYWORD('WITH'), 
     154                     style.SQL_FIELD('1') 
     155                     ) 
     156                ) 
     157        return sql 
     158    else: 
     159        return [] 
     160         
    115161# Register these custom typecasts, because Django expects dates/times to be 
    116162# in Python's native (standard-library) datetime/time format, whereas psycopg 
    117163# use mx.DateTime by default. 
  • django/db/backends/sqlite3/base.py

    old new  
    148148def get_pk_default_value(): 
    149149    return "NULL" 
    150150 
     151def get_sql_flush(style, tables, sequences): 
     152    """Return a list of SQL statements required to remove all data from 
     153    all tables in the database (without actually removing the tables 
     154    themselves) and put the database in an empty 'initial' state 
     155     
     156    """ 
     157    # NB: The generated SQL below is specific to SQLite 
     158    # Note: The DELETE FROM... SQL generated below works for SQLite databases 
     159    # because constraints don't exist 
     160    sql = ['%s %s %s;' % \ 
     161            (style.SQL_KEYWORD('DELETE'), 
     162             style.SQL_KEYWORD('FROM'), 
     163             style.SQL_FIELD(quote_name(table)) 
     164             ) for table in tables] 
     165    # Note: No requirement for reset of auto-incremented indices (cf. other 
     166    # get_sql_flush() implementations). Just return SQL at this point 
     167    return sql 
     168 
    151169def _sqlite_date_trunc(lookup_type, dt): 
    152170    try: 
    153171        dt = util.typecast_timestamp(dt) 
  • django/db/backends/mysql/base.py

    old new  
    181181def get_pk_default_value(): 
    182182    return "DEFAULT" 
    183183 
     184def get_sql_flush(style, tables, sequences): 
     185    """Return a list of SQL statements required to remove all data from 
     186    all tables in the database (without actually removing the tables 
     187    themselves) and put the database in an empty 'initial' state 
     188     
     189    """ 
     190    # NB: The generated SQL below is specific to MySQL 
     191    # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements 
     192    # to clear all tables of all data 
     193    if tables: 
     194        sql = ['%s %s;' % \ 
     195                (style.SQL_KEYWORD('TRUNCATE'), 
     196                 style.SQL_FIELD(quote_name(table)) 
     197                )  for table in tables] 
     198        # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements 
     199        # to reset sequence indices 
     200        sql.extend(["%s %s %s %s %s;" % \ 
     201            (style.SQL_KEYWORD('ALTER'), 
     202             style.SQL_KEYWORD('TABLE'), 
     203             style.SQL_TABLE(quote_name(sequence['table'])), 
     204             style.SQL_KEYWORD('AUTO_INCREMENT'), 
     205             style.SQL_FIELD('= 1'), 
     206            ) for sequence in sequences]) 
     207        return sql 
     208    else: 
     209        return [] 
     210 
    184211OPERATOR_MAPPING = { 
    185212    'exact': '= %s', 
    186213    'iexact': 'LIKE %s', 
  • django/db/backends/oracle/base.py

    old new  
    117117def get_pk_default_value(): 
    118118    return "DEFAULT" 
    119119 
     120def get_sql_flush(style, tables, sequences): 
     121    """Return a list of SQL statements required to remove all data from 
     122    all tables in the database (without actually removing the tables 
     123    themselves) and put the database in an empty 'initial' state 
     124    """ 
     125    # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements 
     126    # TODO - SQL not actually tested against Oracle yet! 
     127    # TODO - autoincrement indices reset required? See other get_sql_flush() implementations 
     128    sql = ['%s %s;' % \ 
     129            (style.SQL_KEYWORD('TRUNCATE'), 
     130             style.SQL_FIELD(quote_name(table)) 
     131             )  for table in tables] 
     132 
     133 
    120134OPERATOR_MAPPING = { 
    121135    'exact': '= %s', 
    122136    'iexact': 'LIKE %s', 
  • django/db/backends/postgresql_psycopg2/base.py

    old new  
    105105def get_pk_default_value(): 
    106106    return "DEFAULT" 
    107107 
     108def get_sql_flush(style, tables, sequences): 
     109    """Return a list of SQL statements required to remove all data from 
     110    all tables in the database (without actually removing the tables 
     111    themselves) and put the database in an empty 'initial' state 
     112    """ 
     113    # Postgres can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to 
     114    # truncate tables referenced by a foreign key in any other table. The result is a 
     115    # single SQL TRUNCATE statement 
     116    if tables: 
     117        sql = ['%s %s;' % \ 
     118                (style.SQL_KEYWORD('TRUNCATE'), 
     119                 style.SQL_FIELD(', '.join(quote_name(table) for table in tables)) 
     120                )] 
     121        # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements 
     122        # to reset sequence indices 
     123        for sequence in sequences: 
     124            table_name = sequence['table'] 
     125            column_name = sequence['column'] 
     126            if column_name and len(column_name) > 0: 
     127                # sequence name in this case will be <table>_<column>_seq 
     128                sql.append("%s %s %s %s %s %s;" % \ 
     129                    (style.SQL_KEYWORD('ALTER'), 
     130                     style.SQL_KEYWORD('SEQUENCE'), 
     131                     style.SQL_FIELD('%s_%s_seq' % (table_name, column_name)), 
     132                     style.SQL_KEYWORD('RESTART'), 
     133                     style.SQL_KEYWORD('WITH'), 
     134                     style.SQL_FIELD('1') 
     135                     ) 
     136                ) 
     137            else: 
     138                # sequence name in this case will be <table>_id_seq 
     139                sql.append("%s %s %s %s %s %s;" % \ 
     140                    (style.SQL_KEYWORD('ALTER'), 
     141                     style.SQL_KEYWORD('SEQUENCE'), 
     142                     style.SQL_FIELD('%s_id_seq' % table_name), 
     143                     style.SQL_KEYWORD('RESTART'), 
     144                     style.SQL_KEYWORD('WITH'), 
     145                     style.SQL_FIELD('1') 
     146                     ) 
     147                ) 
     148        return sql 
     149    else: 
     150        return [] 
     151         
    108152OPERATOR_MAPPING = { 
    109153    'exact': '= %s', 
    110154    'iexact': 'ILIKE %s', 
  • django/db/backends/dummy/base.py

    old new  
    3838get_random_function_sql = complain 
    3939get_fulltext_search_sql = complain 
    4040get_drop_foreignkey_sql = complain 
     41get_sql_flush = complain 
     42 
    4143OPERATOR_MAPPING = {} 
  • django/core/serializers/base.py

    old new  
    141141 
    142142class DeserializedObject(object): 
    143143    """ 
    144     A deserialzed model. 
     144    A deserialized model. 
    145145 
    146146    Basically a container for holding the pre-saved deserialized data along 
    147147    with the many-to-many data saved with the object. 
  • django/core/management.py

    old new  
    6868    cursor = connection.cursor() 
    6969    return get_introspection_module().get_table_list(cursor) 
    7070 
     71def _get_sequence_list(): 
     72    "Returns a list of information about all DB sequences for all models in all apps" 
     73    from django.db import models 
     74 
     75    apps = models.get_apps() 
     76    sequence_list = [] 
     77 
     78    for app in apps: 
     79        for model in models.get_models(app): 
     80            for f in model._meta.fields: 
     81                if isinstance(f, models.AutoField): 
     82                    sequence_list.append({'table':model._meta.db_table,'column':f.column,}) 
     83                    break # Only one AutoField is allowed per model, so don't bother continuing. 
     84 
     85            for f in model._meta.many_to_many: 
     86                sequence_list.append({'table':f.m2m_db_table(),'column':None,}) 
     87 
     88    return sequence_list 
     89 
    7190# If the foreign key points to an AutoField, a PositiveIntegerField or a 
    7291# PositiveSmallIntegerField, the foreign key should be an IntegerField, not the 
    7392# referred field type. Otherwise, the foreign key should be the same type of 
     
    330349get_sql_reset.help_doc = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)." 
    331350get_sql_reset.args = APP_ARGS 
    332351 
    333 def get_sql_initial_data_for_model(model): 
     352def get_sql_flush(): 
     353    "Returns a list of the SQL statements used to flush the database" 
     354    from django.db import backend 
     355    statements = backend.get_sql_flush(style, _get_table_list(), _get_sequence_list()) 
     356    return statements 
     357get_sql_flush.help_doc = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed." 
     358get_sql_flush.args = '' 
     359 
     360def get_custom_sql_for_model(model): 
    334361    from django.db import models 
    335362    from django.conf import settings 
    336363 
     
    357384 
    358385    return output 
    359386 
    360 def get_sql_initial_data(app): 
    361     "Returns a list of the initial INSERT SQL statements for the given app." 
     387def get_custom_sql(app): 
     388    "Returns a list of the custom table modifying SQL statements for the given app." 
    362389    from django.db.models import get_models 
    363390    output = [] 
    364391 
     
    366393    app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql')) 
    367394 
    368395    for model in app_models: 
    369         output.extend(get_sql_initial_data_for_model(model)) 
     396        output.extend(get_custom_sql_for_model(model)) 
    370397 
    371398    return output 
    372 get_sql_initial_data.help_doc = "Prints the initial INSERT SQL statements for the given app name(s)." 
    373 get_sql_initial_data.args = APP_ARGS 
     399get_custom_sql.help_doc = "Prints the custom table modifying SQL statements for the given app name(s)." 
     400get_custom_sql.args = APP_ARGS 
    374401 
    375402def get_sql_sequence_reset(app): 
    376403    "Returns a list of the SQL statements to reset PostgreSQL sequences for the given app." 
     
    428455 
    429456def get_sql_all(app): 
    430457    "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module." 
    431     return get_sql_create(app) + get_sql_initial_data(app) + get_sql_indexes(app) 
     458    return get_sql_create(app) + get_custom_sql(app) + get_sql_indexes(app) 
    432459get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)." 
    433460get_sql_all.args = APP_ARGS 
    434461 
     
    511538        # just created) 
    512539        for model in models.get_models(app): 
    513540            if model in created_models: 
    514                 initial_sql = get_sql_initial_data_for_model(model) 
     541                initial_sql = get_custom_sql_for_model(model) 
    515542                if initial_sql: 
    516543                    if verbosity >= 1: 
    517                         print "Installing initial data for %s.%s model" % (app_name, model._meta.object_name) 
     544                        print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name) 
    518545                    try: 
    519546                        for sql in initial_sql: 
    520547                            cursor.execute(sql) 
     
    670697reset.help_doc = "Executes ``sqlreset`` for the given app(s) in the current database." 
    671698reset.args = APP_ARGS 
    672699 
     700def flush(verbosity=1, interactive=True): 
     701    "Returns all tables in the database to the same state they were in immediately after syncdb." 
     702    from django.db import connection, transaction, models 
     703    from django.conf import settings 
     704    from django.dispatch import dispatcher 
     705     
     706    disable_termcolors() 
     707 
     708    # First, try validating the models. 
     709    _check_for_validation_errors() 
     710 
     711    # Import the 'management' module within each installed app, to register 
     712    # dispatcher events. 
     713    for app_name in settings.INSTALLED_APPS: 
     714        try: 
     715            __import__(app_name + '.management', {}, {}, ['']) 
     716        except ImportError: 
     717            pass 
     718     
     719    sql_list = get_sql_flush() 
     720 
     721    if interactive: 
     722        confirm = raw_input(""" 
     723You have requested a flush of the database. 
     724This will IRREVERSIBLY DESTROY all data currently in the database, 
     725and return each table to the state it was in after syncdb. 
     726Are you sure you want to do this? 
     727 
     728Type 'yes' to continue, or 'no' to cancel: """) 
     729    else: 
     730        confirm = 'yes' 
     731 
     732    if confirm == 'yes': 
     733        try: 
     734            cursor = connection.cursor() 
     735            for sql in sql_list: 
     736                cursor.execute(sql) 
     737        except Exception, e: 
     738            sys.stderr.write(style.ERROR("""Error: Database %s couldn't be flushed. Possible reasons: 
     739  * The database isn't running or isn't configured correctly. 
     740  * At least one of the expected database tables doesn't exist. 
     741  * The SQL was invalid. 
     742Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run. 
     743The full error: """ % settings.DATABASE_NAME + style.ERROR_OUTPUT(str(e)) + '\n')) 
     744            transaction.rollback_unless_managed() 
     745            sys.exit(1) 
     746        transaction.commit_unless_managed() 
     747 
     748        # Emit the post-syncdb signal for every application. 
     749        # This simulates the effect of installing every application clean. 
     750        for app in models.get_apps(): 
     751            app_name = app.__name__.split('.')[-2] 
     752            model_list = models.get_models(app) 
     753            if verbosity >= 2: 
     754                print "Running post-sync handlers for application", app_name 
     755            dispatcher.send(signal=models.signals.post_syncdb, sender=app, 
     756                app=app, created_models=model_list, 
     757                verbosity=verbosity, interactive=interactive) 
     758         
     759    else: 
     760        print "Flush cancelled." 
     761flush.help_doc = "Executes ``sqlflush`` on the current database." 
     762flush.args = '' 
     763 
    673764def _start_helper(app_or_project, name, directory, other_name=''): 
    674765    other = {'project': 'app', 'app': 'project'}[app_or_project] 
    675766    if not _is_valid_dir_name(name): 
     
    751842    yield "#     * Make sure each model has one field with primary_key=True" 
    752843    yield "# Feel free to rename the models, but don't rename db_table values or field names." 
    753844    yield "#" 
    754     yield "# Also note: You'll have to insert the output of 'django-admin.py sqlinitialdata [appname]'" 
     845    yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'" 
    755846    yield "# into your database." 
    756847    yield '' 
    757848    yield 'from django.db import models' 
     
    12391330test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified' 
    12401331test.args = '[--verbosity] ' + APP_ARGS 
    12411332 
     1333def install_fixtures(fixture_labels, format='json', verbosity=1): 
     1334    "Installs the fixture(s) with the provided name(s)" 
     1335    from django.db.models import get_apps 
     1336    from django.core import serializers 
     1337    from django.db import transaction 
     1338    from django.conf import settings 
     1339    import sys 
     1340      
     1341    # Keep a count of the installed objects and fixtures 
     1342    count = [0,0] 
     1343     
     1344    serializer = serializers.get_serializer(format) 
     1345     
     1346    if verbosity > 1: 
     1347        print "Looking for %s fixtures..." % format 
     1348         
     1349    app_fixtures = [os.path.join(os.path.dirname(app.__file__),'fixtures') for app in get_apps()] 
     1350    for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS): 
     1351        if verbosity > 1: 
     1352            print "Checking '%s' for %s fixtures..." % (fixture_dir, format) 
     1353        for fixture_name in fixture_labels: 
     1354            try: 
     1355                if verbosity > 1: 
     1356                    print "Trying %s fixture '%s' from '%s'." % (format, fixture_name, fixture_dir) 
     1357                fixture = open(os.path.join(fixture_dir, 
     1358                                            '.'.join([fixture_name, format])), 
     1359                               'r') 
     1360                count[1] += 1 
     1361                if verbosity > 0: 
     1362                    print "Installing %s fixture '%s' from '%s'." % (format, fixture_name, fixture_dir) 
     1363                try: 
     1364                    for obj in serializers.deserialize(format, fixture): 
     1365                        count[0] += 1 
     1366                        obj.save() 
     1367                except Exception, e: 
     1368                    sys.stderr.write( 
     1369                        style.ERROR("Problem installing %s fixture '%s' from '%s': %s\n" %  
     1370                             (format, fixture_name, fixture_dir, str(e)))) 
     1371                fixture.close() 
     1372            except: 
     1373                if verbosity > 1: 
     1374                    print "No %s fixture '%s' in '%s'" % (format, fixture_name, fixture_dir) 
     1375    if count[0] == 0: 
     1376        if verbosity > 0: 
     1377            print "No fixtures found" 
     1378    else: 
     1379        if verbosity > 0: 
     1380            print "Installed %d objects from %d fixtures" % tuple(count) 
     1381        transaction.commit_unless_managed() 
     1382install_fixtures.help_doc = 'Installs the named fixture(s) in the database' 
     1383install_fixtures.args = "[--format] [--verbosity] fixture_name, fixture_name, ..." 
     1384  
     1385def dumpdb(app_labels, format='json'): 
     1386    "Output the current contents of the database as a fixture of the given format" 
     1387    from django.db.models import get_app, get_apps, get_models 
     1388    from django.core import serializers 
     1389  
     1390    if len(app_labels) == 0: 
     1391        app_list = get_apps() 
     1392    else: 
     1393        app_list = [get_app(app_label) for app_label in app_labels] 
     1394  
     1395    # Check that the serialization format exists; this is a shortcut to 
     1396    # avoid collating all the objects and _then_ failing. 
     1397    try: 
     1398        serializers.get_serializer(format) 
     1399    except KeyError: 
     1400        sys.stderr.write(style.ERROR("Unknown serialization format: %s\n" % format))         
     1401     
     1402    objects = [] 
     1403    for app in app_list: 
     1404        for model in get_models(app): 
     1405            objects.extend(model.objects.all()) 
     1406    try: 
     1407        print serializers.serialize(format, objects) 
     1408    except Exception, e: 
     1409     sys.stderr.write(style.ERROR("Unable to serialize database: %s\n" % e)) 
     1410dumpdb.help_doc = 'Output the contents of the database as a fixture of the given format' 
     1411dumpdb.args = '[--format]' + APP_ARGS 
     1412 
    12421413# Utilities for command-line script 
    12431414 
    12441415DEFAULT_ACTION_MAPPING = { 
     
    12461417    'createcachetable' : createcachetable, 
    12471418    'dbshell': dbshell, 
    12481419    'diffsettings': diffsettings, 
     1420    'dumpdb': dumpdb, 
     1421    'flush': flush, 
    12491422    'inspectdb': inspectdb, 
    12501423    'install': install, 
     1424    'installfixture': install_fixtures, 
    12511425    'reset': reset, 
    12521426    'runfcgi': runfcgi, 
    12531427    'runserver': runserver, 
     
    12551429    'sql': get_sql_create, 
    12561430    'sqlall': get_sql_all, 
    12571431    'sqlclear': get_sql_delete, 
     1432    'sqlcustom': get_custom_sql, 
     1433    'sqlflush': get_sql_flush, 
    12581434    'sqlindexes': get_sql_indexes, 
    1259     'sqlinitialdata': get_sql_initial_data, 
    12601435    'sqlreset': get_sql_reset, 
    12611436    'sqlsequencereset': get_sql_sequence_reset, 
    12621437    'startapp': startapp, 
     
    13181493        help='Tells Django to NOT prompt the user for input of any kind.') 
    13191494    parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True, 
    13201495        help='Tells Django to NOT use the auto-reloader when running the development server.') 
     1496    parser.add_option('--format', default='json', dest='format', 
     1497        help='Specifies the serialization format for fixtures') 
    13211498    parser.add_option('--verbosity', action='store', dest='verbosity', default='1', 
    13221499        type='choice', choices=['0', '1', '2'], 
    13231500        help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), 
     
    13511528        action_mapping[action](options.plain is True) 
    13521529    elif action in ('validate', 'diffsettings', 'dbshell'): 
    13531530        action_mapping[action]() 
    1354     elif action == 'syncdb'
     1531    elif action in ('flush', 'syncdb')
    13551532        action_mapping[action](int(options.verbosity), options.interactive) 
    13561533    elif action == 'inspectdb': 
    13571534        try: 
     
    13701547            action_mapping[action](args[1:], int(options.verbosity)) 
    13711548        except IndexError: 
    13721549            parser.print_usage_and_exit() 
     1550    elif action == 'installfixture': 
     1551        try: 
     1552            action_mapping[action](args[1:], options.format, int(options.verbosity)) 
     1553        except IndexError: 
     1554            parser.print_usage_and_exit() 
     1555    elif action == 'dumpdb': 
     1556        try: 
     1557            action_mapping[action](args[1:], options.format) 
     1558        except IndexError: 
     1559            parser.print_usage_and_exit()         
    13731560    elif action in ('startapp', 'startproject'): 
    13741561        try: 
    13751562            name = args[1] 
     
    13881575        action_mapping[action](addr, port, options.use_reloader, options.admin_media_path) 
    13891576    elif action == 'runfcgi': 
    13901577        action_mapping[action](args[1:]) 
     1578    elif action == 'sqlflush': 
     1579        print '\n'.join(action_mapping[action]()) 
    13911580    else: 
    13921581        from django.db import models 
    13931582        validate(silent_success=True) 
  • tests/modeltests/fixtures/fixtures/fixture1.json

    old new  
     1[ 
     2    { 
     3        "pk": "1",  
     4        "model": "fixtures.article",  
     5        "fields": { 
     6            "headline": "Poker has no place on ESPN",  
     7            "pub_date": "2006-06-16 11:00:00" 
     8        } 
     9    },  
     10    { 
     11        "pk": "2",  
     12        "model": "fixtures.article",  
     13        "fields": { 
     14            "headline": "Time to reform copyright",  
     15            "pub_date": "2006-06-16 13:00:00" 
     16        } 
     17    } 
     18] 
  • tests/modeltests/fixtures/fixtures/fixture2.json

    old new  
     1[ 
     2    { 
     3        "pk": "2",  
     4        "model": "fixtures.article",  
     5        "fields": { 
     6            "headline": "Copyright is fine the way it is",  
     7            "pub_date": "2006-06-16 14:00:00" 
     8        } 
     9    },  
     10    { 
     11        "pk": "3",  
     12        "model": "fixtures.article",  
     13        "fields": { 
     14            "headline": "Django conquers world!",  
     15            "pub_date": "2006-06-16 15:00:00" 
     16        } 
     17    } 
     18] 
  • tests/modeltests/fixtures/fixtures/fixture3.xml

    old new  
     1<?xml version="1.0" encoding="utf-8"?> 
     2<django-objects version="1.0"> 
     3    <object pk="1" model="fixtures.article"> 
     4        <field type="CharField" name="headline">Poker on TV is great!</field> 
     5        <field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field> 
     6    </object> 
     7    <object pk="4" model="fixtures.article"> 
     8        <field type="CharField" name="headline">XML identified as leading cause of cancer</field> 
     9        <field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field> 
     10    </object> 
     11</django-objects> 
  • tests/modeltests/fixtures/models.py

    old new  
     1""" 
     239. Fixtures. 
     3 
     4Fixtures are a way of loading data into the database in bulk. Fixure data  
     5can be stored in any serializable format (including JSON and XML). Fixtures  
     6are identified by name, and are stored in either a directory named 'fixtures' 
     7in the application directory, on in one of the directories named in the  
     8FIXTURE_DIRS setting. 
     9""" 
     10 
     11from django.db import models 
     12 
     13class Article(models.Model): 
     14    headline = models.CharField(maxlength=100, default='Default headline') 
     15    pub_date = models.DateTimeField() 
     16 
     17    def __str__(self): 
     18        return self.headline 
     19         
     20    class Meta: 
     21        ordering = ('-pub_date', 'headline') 
     22         
     23__test__ = {'API_TESTS': """ 
     24>>> from django.core import management 
     25>>> from django.db.models import get_app 
     26 
     27# Load fixture 1. Single JSON file, with two objects. 
     28>>> management.install_fixtures(['fixture1'], verbosity=0) 
     29>>> Article.objects.all() 
     30[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>] 
     31 
     32# Load fixture 2. JSON file imported by default. Overwrites some existing objects 
     33>>> management.install_fixtures(['fixture2'], verbosity=0) 
     34>>> Article.objects.all() 
     35[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>] 
     36 
     37# Load fixture 3, XML format.  
     38>>> management.install_fixtures(['fixture3'], format='xml', verbosity=0) 
     39>>> Article.objects.all() 
     40[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>] 
     41 
     42# Reset the database representation of this app. This will delete all data. 
     43>>> management.flush(interactive=False) 
     44>>> management.syncdb(verbosity=0, interactive=False) 
     45>>> Article.objects.all() 
     46[] 
     47 
     48# Load fixture 1 again 
     49>>> management.install_fixtures(['fixture1'], verbosity=0) 
     50>>> Article.objects.all() 
     51[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>] 
     52 
     53# Dump the current contents of the database as a JSON fixture 
     54>>> management.dumpdb(['fixtures'], format='json') 
     55[{"pk": "2", "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": "1", "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 11:00:00"}}] 
     56"""} 
     57 
     58from django.test import TestCase 
     59 
     60class SampleTestCase(TestCase): 
     61    fixtures = { 'json': ['fixture1', 'fixture2'] } 
     62         
     63    def testClassFixtures(self): 
     64        "Check that test case has installed 3 fixture objects" 
     65        self.assertEqual(Article.objects.count(), 3) 
     66        self.assertEquals(str(Article.objects.all()), "[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>]") 
  • tests/modeltests/test_client/management.py

    old new  
    1 from django.dispatch import dispatcher 
    2 from django.db.models import signals 
    3 import models as test_client_app 
    4 from django.contrib.auth.models import User 
    5  
    6 def setup_test(app, created_models, verbosity): 
    7     # Create a user account for the login-based tests 
    8     User.objects.create_user('testclient','testclient@example.com', 'password') 
    9  
    10 dispatcher.connect(setup_test, sender=test_client_app, signal=signals.post_syncdb) 
  • tests/modeltests/test_client/fixtures/testdata.json

    old new  
     1[ 
     2    { 
     3        "pk": "1",  
     4        "model": "auth.user",  
     5        "fields": { 
     6            "username": "testclient",  
     7            "first_name": "Test",  
     8            "last_name": "Client",  
     9            "is_active": true,  
     10            "is_superuser": false,  
     11            "is_staff": false,  
     12            "last_login": "2006-12-17 07:03:31",  
     13            "groups": [],  
     14            "user_permissions": [],  
     15            "password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161",  
     16            "email": "testclient@example.com",  
     17            "date_joined": "2006-12-17 07:03:31" 
     18        } 
     19    } 
     20] 
  • tests/modeltests/test_client/models.py

    old new  
    1919rather than the HTML rendered to the end-user. 
    2020 
    2121""" 
    22 from django.test.client import Client 
    23 import unittest 
     22from django.test import Client, TestCase 
    2423 
    25 class ClientTest(unittest.TestCase): 
     24class ClientTest(TestCase): 
     25    fixtures = { 'json': ['testdata'] } 
     26     
    2627    def setUp(self): 
    2728        "Set up test environment" 
    2829        self.client = Client() 
  • tests/urls.py

    old new  
    66 
    77    # Always provide the auth system login and logout views 
    88    (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}), 
    9     (r'^accounts/logout/$', 'django.contrib.auth.views.login'), 
     9    (r'^accounts/logout/$', 'django.contrib.auth.views.logout'), 
    1010)