Ticket #4144: dynamic_models.diff
File dynamic_models.diff, 10.5 KB (added by , 18 years ago) |
---|
-
tests/modeltests/dynamic_models/models.py
1 """ 2 Dynamic Models 3 4 In some cases, it can be useful for models to be created at run-time, 5 rather than being defined in source files. 6 """ 7 8 from django.db import models 9 10 def 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 43 def 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) 73 1 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 88 True 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) 112 3 113 114 # Install a dynamic model in the test database 115 116 >>> install(model) 117 >>> model.objects.count() 118 0 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() 131 3 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() 149 1 150 """} 151 152 class 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 """ 2 Dynamic Models 3 4 In some cases, it can be useful for models to be created at run-time, 5 rather than being defined in source files. 6 """ 7 8 from django.db import models 9 10 def 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 43 def 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) 73 1 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 88 True 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) 112 3 113 114 # Install a dynamic model in the test database 115 116 >>> install(model) 117 >>> model.objects.count() 118 0 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() 131 3 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() 149 1 150 """} 151 152 class 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))