Ticket #2333: fixtures.diff

File fixtures.diff, 34.9 KB (added by Russell Keith-Magee, 17 years ago)

Phase 3, version 1 of the testing framework - fixtures

  • django/test/testcases.py

     
    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

     
     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

     
    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

     
    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

     
    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

     
    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

     
    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

     
    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

     
    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

     
    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

     
    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

     
    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

    Property changes on: tests/modeltests/fixtures
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
    
    Property changes on: tests/modeltests/fixtures/fixtures
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
     
     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]
     19 No newline at end of file
  • tests/modeltests/fixtures/fixtures/fixture2.json

     
     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]
     19 No newline at end of file
  • tests/modeltests/fixtures/fixtures/fixture3.xml

     
     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>
     12 No newline at end of file
  • tests/modeltests/fixtures/models.py

     
     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

     
    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

    Property changes on: tests/modeltests/test_client/fixtures
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
     
     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]
     21 No newline at end of file
  • tests/modeltests/test_client/models.py

     
    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

     
    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)
Back to Top