基于仅存在于新版本中的字段的条件 Django 迁移

Oli*_*Oli 9 django backwards-compatibility django-models django-migrations

我的应用程序目前依赖于 Postgres 和 Django 的 Postgres-only JSONField。该领域运作良好,我对另一个项目不感兴趣,但我有一些潜在用户想要使用我的应用程序,但在它依赖 Postgres 时却不能。

Django 3.1 有这个字段的跨平台版本——它可以满足我的需求——但我不想强迫每个人都使用 Django 3.1;我想为人们提供 Postgres 或 Django 3.1+ 之间的选择。在纸面上,这很简单,有条件导入......

try:
    from django.db.models import JSONField
except ImportError:
    from django.contrib.postgres.fields import JSONField
Run Code Online (Sandbox Code Playgroud)

如果我安装的Django 3.1和产生迁移,它可以把我从django.contrib.postgres.fields.JSONFielddjango.db.models.JSONField。但...

  • 新用户仍将执行初始迁移。我仍然会依赖 Postgres。
  • Sub-Django 3.1 用户将无法执行新的迁移。我现在依赖于 Django 3.1。

这比我开始时更糟。我如何以适合所有人的方式进行这种现场迁移?

Tom*_*ick 8

迁移只是代码。仅仅因为它们是自动生成的并不意味着你不应该改变它们。鼓励您至少检查它们是否正确生成,但自己编写它们也没有坏处。

这对我有用:

模型:

from django.db import models

try:
    from django.db.models import JSONField
except ImportError:
    from django.contrib.postgres.fields import JSONField

class MyModel(models.Model):
    stuff = JSONField()
Run Code Online (Sandbox Code Playgroud)

移民:

from django.db import migrations, models

try:
    from django.db.models import JSONField
except ImportError:
    from django.contrib.postgres.fields import JSONField


class Migration(migrations.Migration):
    dependencies = [('testapp', '0001_initial')]

    operations = [
        migrations.CreateModel(
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('stuff', JSONField()),
            ],
        ),
    ]

Run Code Online (Sandbox Code Playgroud)

请记住,如果您以后需要更改此字段,则需要再次执行此过程。


JPG*_*JPG 5

我从Django 源代码中得到了这个

from django.db.models import JSONField as BuiltinJSONField

class JSONField(BuiltinJSONField):
    system_check_deprecated_details = {
        'msg': (
            'django.contrib.postgres.fields.JSONField is deprecated. Support '
            'for it (except in historical migrations) will be removed in '
            'Django 4.0.'
        ),
        'hint': 'Use django.db.models.JSONField instead.',
        'id': 'fields.W904',
    }
Run Code Online (Sandbox Code Playgroud)

这表明,django.contrib.postgres.fields.JSONField将被弃用。此外,Django 使用django.db.models.JSONFieldas postgres 特殊的 JSONField。

除此之外,我使用sqlmigratecommand生成了 SQL 命令,就像,

BEGIN;
--
-- Create model MyModel
--
CREATE TABLE "myapp_mymodel" ("id" serial NOT NULL PRIMARY KEY, "stuff" jsonb NOT NULL);
COMMIT;
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,我在数据库中使用Django==3.0和获得了相同的 SQL 命令Django==3.1,该字段是一种jsonb类型

这些信息表明您不必担心这个新的 JSONField 升级。

需要做哪些改变?

您不需要生成新的迁移文件,而是编辑django.contrib.postgres.fields.JSONField与该try...except块相关的现有迁移文件。

就是这样!!!