gpt4 book ai didi

python - 如何以编程方式为 Django 中的给定模型生成 CREATE TABLE SQL 语句?

转载 作者:太空狗 更新时间:2023-10-29 21:48:24 26 4
gpt4 key购买 nike

我需要以编程方式为我的 Django 应用程序中给定的 非托管 模型生成 CREATE TABLE 语句 (managed = False)

由于我在遗留数据库上工作,我不想创建迁移并使用 sqlmigrate

./manage.py sql 命令可用于此目的,但已在 Django 1.8 中删除

您知道任何替代方案吗?

最佳答案

按照建议,我发布了案例的完整答案,问题可能暗示了这一点。

假设您有一个外部数据库表,您决定将其作为 Django 模型进行访问,因此将其描述为非托管模型 (Meta: managed = False)。稍后您需要能够在您的代码中创建它,例如使用本地数据库进行一些测试。显然,Django 不会为非托管模型进行迁移,因此不会在您的测试数据库中创建它。这可以使用 Django API 解决,而无需诉诸原始 SQL - SchemaEditor .请参阅下面更完整的示例,但作为简短的回答,您可以像这样使用它:

   from django.db import connections

with connections['db_to_create_a_table_in'].schema_editor() as schema_editor:
schema_editor.create_model(YourUnmanagedModelClass)

一个实际的例子:

# your_app/models/your_model.py

from django.db import models

class 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):
"""Preventing data modification."""
pass

def delete(self, *args, **kwargs):
"""Preventing data deletion."""
pass

现在,假设您需要能够通过 Django 创建此模型,例如进行一些测试。

# your_app/tests/some_test.py

# This will allow to access the `SchemaEditor` for the DB
from django.db import connections
from django.test import TestCase
from your_app.models.your_model import IntegrationView

class 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):
"""Prepares `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',
))

为了使示例更完整...因为我们使用多个数据库(defaultexternal_db)Django 将尝试在它们上运行迁移测试,截至目前,数据库设置中没有选项可以防止这种情况发生。所以我们必须使用自定义数据库路由器进行测试。

 # your_app/tests/base.py

class 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

以及所描述案例的测试设置文件示例:

# settings/test.py

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'db_name',
'USER': 'username',
'HOST': 'localhost',
'PASSWORD': 'password',
'PORT': '1521',
},
# 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` DB
DATABASE_ROUTERS = ['your_app.tests.base.PreventMigrationsDBRouter', ]

希望这个详细的新 Django 用户友好示例能够帮助某人并节省他们的时间。

关于python - 如何以编程方式为 Django 中的给定模型生成 CREATE TABLE SQL 语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48666334/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com