Ticket #4144: dynamic_models.diff

File dynamic_models.diff, 10.5 KB (added by Marty Alchin <gulopine@…>, 17 years ago)

Some basic tests for dynamic models

  • tests/modeltests/dynamic_models/models.py

     
     1"""
     2Dynamic Models
     3
     4In some cases, it can be useful for models to be created at run-time,
     5rather than being defined in source files.
     6"""
     7
     8from django.db import models
     9
     10def create_model(name, fields=None, app_label='', module='', options=None, admin=None):
     11    "One example of how to create a model dynamically at run-time"
     12
     13    app_name = app_label
     14
     15    # app_label must be set using the Meta inner class
     16    class Meta:
     17        # Using type('Meta', ...) gives a dictproxy error during model creation
     18        app_label = app_name
     19
     20    # Update Meta with any options that were provided
     21    if options is not None:
     22        for key, value in options.items():
     23            setattr(Meta, key, value)
     24
     25    # Set up a dictionary to simulate declarations within a class
     26    attrs = {'__module__': module, 'Meta': Meta}
     27
     28    # Add in any fields that were provided
     29    if fields:
     30        attrs.update(fields)
     31
     32    # Create an Admin inner class if admin options were provided
     33    if admin is not None:
     34        class Admin:
     35            pass
     36        for key, value in admin:
     37            setattr(Admin, key, value)
     38        attrs['Admin'] = Admin
     39
     40    # Create the class, which automatically triggers ModelBase processing
     41    return type(name, (models.Model,), attrs)
     42
     43def install(model):
     44    from django.core import management
     45    from django.db import connection
     46
     47    # Standard syncdb expects models to be in reliable locations,
     48    # so dynamic models need to bypass django.core.management.syncdb.
     49    # On the plus side, this allows individual models to be installed
     50    # without installing the entire project structure.
     51    # On the other hand, this means that things like relationships and
     52    # indexes will have to be handled manually.
     53    # For these tests, just the basic table will be installed.
     54
     55    cursor = connection.cursor()
     56    statements, pending = management._get_sql_model_create(model)
     57    for sql in statements:
     58        cursor.execute(sql)
     59
     60__test__ = {'API_TESTS':"""
     61# Create an empty model and make sure it works as expected
     62
     63>>> model = create_model('EmptyModel')
     64>>> model.__name__
     65'EmptyModel'
     66>>> model.__module__
     67''
     68>>> model._meta.app_label
     69''
     70
     71# ID is added automatically
     72>>> len(model._meta.fields)
     731
     74
     75# Create a model with custom references
     76
     77>>> model = create_model('CustomModel', app_label='dynamic_models', module='tests.dynamic_models.models')
     78>>> model.__name__
     79'CustomModel'
     80>>> model.__module__
     81'tests.dynamic_models.models'
     82>>> model._meta.app_label
     83'dynamic_models'
     84
     85# Check that the model was correctly registered with Django
     86>>> from django.db.models import loading
     87>>> loading.get_model('dynamic_models', 'CustomModel') == model
     88True
     89
     90# Create a model with some Meta options
     91
     92>>> meta = {
     93...     'db_table': 'dynamic_table',
     94...     'verbose_name': 'dynamic model',
     95... }
     96>>> model = create_model('MetaModel', options=meta)
     97>>> model._meta.verbose_name
     98'dynamic model'
     99>>> model._meta.verbose_name_plural
     100'dynamic models'
     101
     102# Create a model with some fields
     103
     104>>> fields = {
     105...     'name': models.CharField(maxlength=255),
     106...     'age': models.SmallIntegerField(null=True),
     107... }
     108>>> model = create_model('FieldModel', fields)
     109
     110# ID is added automatically
     111>>> len(model._meta.fields)
     1123
     113
     114# Install a dynamic model in the test database
     115
     116>>> install(model)
     117>>> model.objects.count()
     1180
     119
     120# Test basic CRUD features of a dynamic model
     121
     122# CREATE
     123
     124>>> test1 = model.objects.create(name='Test Object', age=25)
     125>>> test2 = model.objects.create(name='Another Test')
     126>>> test3 = model.objects.create(age=30)
     127
     128# SELECT
     129
     130>>> model.objects.count()
     1313
     132>>> for obj in model.objects.all():
     133...     assert isinstance(obj, model), 'This should not fail'
     134
     135# UPDATE
     136
     137>>> test1.name = 'Updated Object'
     138>>> test1.save()
     139>>> test2.age = 15
     140>>> test2.save()
     141
     142# DELETE
     143
     144>>> test3.delete()
     145
     146# A more advanced query for good measure
     147
     148>>> model.objects.filter(age__gt=20).count()
     1491
     150"""}
     151       
     152class DynamicModelTestCase(object):
     153
     154    def test_options(self):
     155        "Create a model with some Meta options"
     156
     157        meta = {
     158            'db_table': 'dynamic_table',
     159            'verbose_name': 'dynamic model',
     160        }
     161
     162        model = create_model('MetaModel', options=meta)
     163
     164        # Make sure the verbose names were set proper
     165        self.assertEquals(model._meta.verbose_name, 'dynamic model')
     166        self.assertEquals(model._meta.verbose_name_plural, 'dynamic models')
     167
     168        # Install the model to make sure db_table works
     169        install(model)
     170
     171        # Test it out
     172        model.objects.create()
     173        model.objects.create()
     174
     175        for obj in model.objects.all():
     176            self.assert_(isinstance(obj, model))
  • tests/modeltests/dynamic_models/models.py

     
     1"""
     2Dynamic Models
     3
     4In some cases, it can be useful for models to be created at run-time,
     5rather than being defined in source files.
     6"""
     7
     8from django.db import models
     9
     10def create_model(name, fields=None, app_label='', module='', options=None, admin=None):
     11    "One example of how to create a model dynamically at run-time"
     12
     13    app_name = app_label
     14
     15    # app_label must be set using the Meta inner class
     16    class Meta:
     17        # Using type('Meta', ...) gives a dictproxy error during model creation
     18        app_label = app_name
     19
     20    # Update Meta with any options that were provided
     21    if options is not None:
     22        for key, value in options.items():
     23            setattr(Meta, key, value)
     24
     25    # Set up a dictionary to simulate declarations within a class
     26    attrs = {'__module__': module, 'Meta': Meta}
     27
     28    # Add in any fields that were provided
     29    if fields:
     30        attrs.update(fields)
     31
     32    # Create an Admin inner class if admin options were provided
     33    if admin is not None:
     34        class Admin:
     35            pass
     36        for key, value in admin:
     37            setattr(Admin, key, value)
     38        attrs['Admin'] = Admin
     39
     40    # Create the class, which automatically triggers ModelBase processing
     41    return type(name, (models.Model,), attrs)
     42
     43def install(model):
     44    from django.core import management
     45    from django.db import connection
     46
     47    # Standard syncdb expects models to be in reliable locations,
     48    # so dynamic models need to bypass django.core.management.syncdb.
     49    # On the plus side, this allows individual models to be installed
     50    # without installing the entire project structure.
     51    # On the other hand, this means that things like relationships and
     52    # indexes will have to be handled manually.
     53    # For these tests, just the basic table will be installed.
     54
     55    cursor = connection.cursor()
     56    statements, pending = management._get_sql_model_create(model)
     57    for sql in statements:
     58        cursor.execute(sql)
     59
     60__test__ = {'API_TESTS':"""
     61# Create an empty model and make sure it works as expected
     62
     63>>> model = create_model('EmptyModel')
     64>>> model.__name__
     65'EmptyModel'
     66>>> model.__module__
     67''
     68>>> model._meta.app_label
     69''
     70
     71# ID is added automatically
     72>>> len(model._meta.fields)
     731
     74
     75# Create a model with custom references
     76
     77>>> model = create_model('CustomModel', app_label='dynamic_models', module='tests.dynamic_models.models')
     78>>> model.__name__
     79'CustomModel'
     80>>> model.__module__
     81'tests.dynamic_models.models'
     82>>> model._meta.app_label
     83'dynamic_models'
     84
     85# Check that the model was correctly registered with Django
     86>>> from django.db.models import loading
     87>>> loading.get_model('dynamic_models', 'CustomModel') == model
     88True
     89
     90# Create a model with some Meta options
     91
     92>>> meta = {
     93...     'db_table': 'dynamic_table',
     94...     'verbose_name': 'dynamic model',
     95... }
     96>>> model = create_model('MetaModel', options=meta)
     97>>> model._meta.verbose_name
     98'dynamic model'
     99>>> model._meta.verbose_name_plural
     100'dynamic models'
     101
     102# Create a model with some fields
     103
     104>>> fields = {
     105...     'name': models.CharField(maxlength=255),
     106...     'age': models.SmallIntegerField(null=True),
     107... }
     108>>> model = create_model('FieldModel', fields)
     109
     110# ID is added automatically
     111>>> len(model._meta.fields)
     1123
     113
     114# Install a dynamic model in the test database
     115
     116>>> install(model)
     117>>> model.objects.count()
     1180
     119
     120# Test basic CRUD features of a dynamic model
     121
     122# CREATE
     123
     124>>> test1 = model.objects.create(name='Test Object', age=25)
     125>>> test2 = model.objects.create(name='Another Test')
     126>>> test3 = model.objects.create(age=30)
     127
     128# SELECT
     129
     130>>> model.objects.count()
     1313
     132>>> for obj in model.objects.all():
     133...     assert isinstance(obj, model), 'This should not fail'
     134
     135# UPDATE
     136
     137>>> test1.name = 'Updated Object'
     138>>> test1.save()
     139>>> test2.age = 15
     140>>> test2.save()
     141
     142# DELETE
     143
     144>>> test3.delete()
     145
     146# A more advanced query for good measure
     147
     148>>> model.objects.filter(age__gt=20).count()
     1491
     150"""}
     151       
     152class DynamicModelTestCase(object):
     153
     154    def test_options(self):
     155        "Create a model with some Meta options"
     156
     157        meta = {
     158            'db_table': 'dynamic_table',
     159            'verbose_name': 'dynamic model',
     160        }
     161
     162        model = create_model('MetaModel', options=meta)
     163
     164        # Make sure the verbose names were set proper
     165        self.assertEquals(model._meta.verbose_name, 'dynamic model')
     166        self.assertEquals(model._meta.verbose_name_plural, 'dynamic models')
     167
     168        # Install the model to make sure db_table works
     169        install(model)
     170
     171        # Test it out
     172        model.objects.create()
     173        model.objects.create()
     174
     175        for obj in model.objects.all():
     176            self.assert_(isinstance(obj, model))
Back to Top