Qingquan-Li / blog

My Blog
https://Qingquan-Li.github.io/blog/
132 stars 16 forks source link

Django 连接已存在的数据库(以 MySQL 为例)自动生成 models,并伪造数据库迁移 #143

Open Qingquan-Li opened 4 years ago

Qingquan-Li commented 4 years ago

环境:

参考:

# 在 Django 项目的 settings.py 模块中配置好 MySQL 连接设置后,执行以下命令。
# create models by introspecting(内省) an existing database:
$ python manage.py inspectdb > models.py
# introspecting(内省),也叫类型内省,是在运行时进行的一种对象检测机制。
# 我们可以通过内省来获取一个对象的所有信息,比如这个对象的类型,其中包含哪些属性等等。

执行上一步,使用已有的数据库生成 models 后,执行下面数据库迁移命令。参考:

# 生成数据库迁移( app_label 是 Django 项目中的 APP 名称,选填)
# 注意需要先在 settings.py 的 INSTALLED_APPS 中添加 app_label
$ python manage.py makemigrations app_label

# 查看所有迁移
$ python manage.py showmigrations

# 应用数据库生成。由于数据库表已存在,无法应用初始迁移。
# 使用 --fake-initial 选项伪造此迁移。此时实际上只是添加了一条迁移记录,实际上并没有应用迁移。
$ python manage.py migrate --fake-initial app_label

# 还可以伪造迁移 app_label/migrations 下的某条记录(使用场景:再次使用旧有的数据库表生成 models ),例如:
$ python manage.py migrate --fake app_label 0001_initial

注意: 执行 $ python manage.py inspectdb > models.py 并使用其中的 model 应用(伪造)数据库迁移,此后,修改 model 中的字段之后可能无法生成新的数据库迁移记录。 此时,删除(或注释)model ,然后生成并应用数据库迁移(应用 delete model 的迁移记录);然后再还原修改过的 model ,即可成功生成和应用数据库迁移(应用 create model 的迁移记录)。

注意: 如果同一个 models.py 下有多个 model ,此时再次使用旧有的数据库表生成 models 之后,生成数据库迁移并伪造迁移这条记录之后,需要执行以下命令,才能在 Admin 管理后台为其他管理员设置这个 model 的权限。

$ python manage.py migrate app_label


附:

“Django 连接已存在的数据库(以 MySQL 为例)自动生成 models,并伪造数据库迁移”通常在本地环境而非生产环境(服务器环境)中进行。

所以部署 Django 项目到服务器时,并且本地使用的 MySQL 和生产环境的 MySQL 数据库是分离的,此时在 Django 项目的 settings.py 模块中配置好线上生产环境的 MySQL 连接设置(注释掉本地环境的 MySQL 连接配置)后,只需要执行以下正常的数据库迁移命令,不需要“伪造数据库迁移”:

$ python manage.py makemigrations
$ python manage.py migrate

如果在执行上面 $ python manage.py migrate 命令后,出现以下报错:

django.db.utils.IntegrityError: (1215, 'Cannot add foreign key constraint')

参考:https://stackoverflow.com/questions/28561458/django-mysql-error-when-creating-tables ,请先执行:

$ python manage.py migrate auth

然后再次执行:

$ python manage.py migrate


附:在项目中新建一个 app ,并第二次使用原来的某个数据库表(model)(作为外键使用)


在 Django 模型的 Meta 类( class Meta )中, managed 的默认值为 True 。 Django 会自动根据模型类生成映射的数据库表(对象关系映射 Object Relational Mapping,简称ORM)。

managed = True 时,Django 管理这些数据库表的生命周期。 Django 可以对数据库表进行创建、修改(migrations、migrate)和删除。

managed = False 告诉 Django 不要管理这些数据表的创建、修改和删除。


在项目中新建一个 app:

$ python manage.py startapp app02


在 app02/models.py 中第二次使用数据库原有的某个数据库表(model),主要是作为外键使用:

# This is an auto-generated Django model.
# 根据原有的数据库(这里是 MySQL)自定生成 model 的命令:$ python manage.py inspectdb > models.py
# 在项目根目录中生成一个 models.py 文件,这个 OmCustomer 类是从 models.py 中复制的。
class OmCustomer(models.Model):
    id = models.CharField(primary_key=True, max_length=40)
    created_by = models.CharField(max_length=40)
    ... ...

    class Meta:
        managed = False
        db_table = 'om_customer'

因为这个 model(数据表)已经被项目中另一个 app01 使用并管理了( managed = True ),如果此处注释掉 managed = False ,执行以下命令将会报错:

$ python manage.py makemigrations app02
SystemCheckError: System check identified some issues:

ERRORS: om_customer: (models.E028) db_table 'om_customer' is used by multiple models: app01.OmCustomer, app02.OmCustomer.