回答

收藏

如何编程?Django生成给定模型CREATE TABLE SQL语句?

技术问答 技术问答 261 人阅读 | 0 人回复 | 2023-09-14

我需要编程Django给定 在应用()中非托管    模型生成CREATE TABLE语句managed = False- x; e) I( ^5 [( ]
因为我在使用旧数据库,我不想创建迁移和使用它sqlmigrate。
& v6 t7 s2 m) L  K& q, e该./manage.py sql命令对这个目的很有用,但已经存在了Django 1.8中删除。7 _4 W% J/ x3 A- O- Q: ]
你知道其他选择吗?
( u2 ^% S5 v* E& l                                                                ) s& H) @  k, F3 K4 u
    解决方案:                                                                1 g  G" |) N& \! P7 x
                                                                我对此案作出了完整的回答,这可能暗示了这一点。" c& L% Y# ?5 ^5 Z* |6 h+ V- W
假设你有一个外部数据库表,你决定把它当作Django访问模型时,将其描述为非托管模型(Meta: managed =False)。在未来,您需要能够在代码中创建它,例如,使用本地数据库进行某些测试。Django非托管模型不会迁移,因此不会在测试数据库中创建。Django
1 i4 G, i( i5 q' ~' i" hAPI解决这个问题而不使用原始问题SQL-
( S) c7 [- [1 m  O4 BSchemaEditor。请参考以下更完整的例子,但作为一个简短的答案,您可以使用它:9 D% i( S; b* t  n( c( N7 T
            from django.db import connections   with connections['db_to_create_a_table_in'].schema_editor() as schema_editor:        schema_editor.create_model(YourUnmanagedModelClass)实例:
$ k" k$ F( C' w% r# your_app/models/your_model.pyfrom django.db import modelsclass IntegrationView(models.Model):    """A read-only model to access a view in some external DB."""    class Meta:        managed = False        db_table = 'integration_view'    name = models.CharField(         db_column='object_name         max_length=255,         primaty_key=True,       verbose_name='Object Name some_value = models.CharField(         db_column='some_object_value',                            max_length=255,         blank=True,       null=True,       verbose_name='Some Object Value',   )    # Depending on the situation it might be a good idea to redefine    # some methods as a NOOP as a safety-net.    # Note,that it's not completely safe this way,but might help with some    # silly mistakes in user code    def save(self,*args,**kwargs):        ""&quotreventing data modification."""        pass    def delete(self,*args,**kwargs):        ""&quotreventing data deletion."""        pass假设你现在需要能够通过Django例如,在某些测试中创建此模型。
& f7 N) _2 ?3 Q) U3 A# your_app/tests/some_test.py# This will allow to access the `SchemaEditor` for the DBfrom django.db import connectionsfrom django.test import TestCasefrom your_app.models.your_model import IntegrationViewclass SomeLogicTestCase(TestCase):    """Tests some logic,that uses `IntegrationView`."""    # Since it is assumed,that the `IntegrationView` is read-only for the    # the case being described it's a good idea to put setup logic in class     # setup fixture,that will run only once for the whole test case    @classmethod    def setUpClass(cls):        ""&quotrepares `IntegrationView` mock data for the test case."""        # This is the actual part,that will create the table in the DB        # for the unmanaged model (Any model in fact,but managed models will        # have their tables created already by the Django testing framework)        # Note: Here we're able to choose which DB,defined in your settings,       # will be used to create the table        with connections['external_db'].schema_editor() as schema_editor:            schema_editor.create_model(IntegrationView)        # That's all you need,after the execution of this statements        # a DB table for `IntegrationView` will be created in the DB        # defined as `external_db`.        # Now suppose we need to add some mock data...        # Again,if we consider the table to be read-only,the data can be         # defined here,otherwise it's better to do it in `setUp()` method.        # Remember `IntegrationView.save()` is overridden as a NOOP,so simple        # calls to `IntegrationView.save()` or `IntegrationView.objects.create()`        # won't do anything,so we need to "Improvise. Adapt. Overcome."        # One way is to use the `save()` method of the base class,                            # but provide the instance of our class        integration_view = IntegrationView(               name='Biggus Dickus  some_value='Something really important.        super(IntegrationView,integration_view).save(using='external_db        # Another one is to use the `bulk_create()`,which doesn't use        # `save()` internally,and in fact is a better solution        # if we're creating many records        IntegrationView.objects.using('external_db').bulk_create([                                                               IntegrationView(                   name='Sillius Soddus',    some_value='Something important           IntegrationView(               name='Naughtius Maximus      some_value='Whatever          # Don't forget to clean after    @classmethod    def tearDownClass(cls):        with connections['external_db'].schema_editor() as schema_editor:            schema_editor.delete_model(IntegrationView)    def test_some_logic_using_data_from_integration_view(self):         self.assertTrue(IntegrationView.objects.using('external_db').filter(               name='Biggus Dickus',        ))使示例更加完整…因为我们使用多个数据库(default和external_db),Django将尝试在两个数据库上运行迁移进行测试。到目前为止,数据库设置中没有选项可以阻止这种情况。因此,我们必须使用自定义DB测试路由器。, d9 t* a- M7 F& O9 Z
    # your_app/tests/base.pyclass PreventMigrationsDBRouter:    """DB router to prevent migrations for specific DBs during tests."""    _NO_MIGRATION_DBS = {'external_db}     def allow_migrate(self,db,app_label,model_name=None,**hints):        """Actually disallows migrations for specific DBs."""        return db not in self._NO_MIGRATION_DBS并根据上述情况提供测试设置文件示例:8 u. Y" s  |( w" _
# settings/test.pyDATABASES =    default ENGINE': 'django.db.backends.oracle NAME': 'db_name USER': 'username HOST': 'localhost PASSWORD': 'password PORT # For production here we would have settings to connect to the external DB,   # but for testing purposes we could get by with an SQLite DB   external_db ENGINE': 'django.db.backends.sqlite3',            # Not necessary to use a router in production config,since if the DB # is unspecified explicitly for some action Django will use the `default` DBDATABASE_ROUTERS = ['your_app.tests.base.PreventMigrationsDBRouter',]希望这个细节,新的Django用户友好示例可以帮助某人,节省他们的时间。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则