これは私がチェック制約のpostgresのために書く生のクエリです
ALTER TABLE rea_asplinkage ADD CONSTRAINT asp_sub_project_positive_integer
CHECK (
jsonb_typeof(linkage-> 'root' -> 'in_sub_project') is not distinct from 'number'
and (linkage->'root'->>'in_sub_project')::numeric % 1 = 0
and (linkage->'root'->>'in_sub_project')::numeric > 0
);
そして、私が移行を作成する方法はこの方法です
# Generated by Django 2.2.10 on 2020-05-16 12:59
from Django.db import connection, migrations
class Migration(migrations.Migration):
dependencies = [("rea", "0029_asplinkage")]
operations = [
migrations.RunSQL(
sql="""
ALTER TABLE rea_asplinkage ADD CONSTRAINT asp_sub_project_positive_integer
CHECK (
jsonb_typeof(linkage-> 'root' -> 'in_sub_project') is not distinct from 'number'
and (linkage->'root'->>'in_sub_project')::numeric % 1 = 0
and (linkage->'root'->>'in_sub_project')::numeric > 0
);
""",
reverse_sql="""
ALTER TABLE rea_asplinkage DROP CONSTRAINT "asp_sub_project_positive_integer";
""",
)
]
そして、これはうまくいきます。
しかし、これは私の元のモデルがASPLinkageモデルのclass Meta
に制約を示さないことを意味します
class ASPLinkage(TimeStampedModel, SoftDeletableModel, PersonStampedModel, OrganizationOwnedModel):
linkage = JSONField(default=default_linkage_for_asp)
objects = OrganizationOwnedSoftDeletableManager()
クラスメタ内に制約を作成するためにExpressionWrapper
とRawSQL
を試しましたが、それでも機能しません。
参考までに、私は https://github.com/Django/django/blob/master/tests/constraints/models.py#L12 にある例を見てきました
https://realpython.com/create-Django-index-without-downtime/#when-Django-generates-a-new-migration を使用して、データベースと状態の個別の移行も確認しました
しかし、私はまだそれを機能させることができません
これは可能ですか?
読みやすくするために質問の概要を書きましょう。
Django 2.2でそれを達成するために 2つの新しいJSONField
変換/ルックアップを登録する必要があります 以降 条件式のサポート次の3.1リリースでのみ追加されました 。
最初に、JSONField
キーアクセスのルックアップを登録する必要があります
_from Django.db import models
from Django.db.models.lookups import Lookup
from Django.contrib.postgres.fields.jsonb import (
KeyTransform, KeyTransformTextLookupMixin
)
@KeyTransform.register_lookup
class KeyTransformIsInteger(KeyTransformTextLookupMixin, Lookup):
lookup_name = 'is_int'
prepare_rhs = False
def as_sql(self, compiler, connection):
key_expr = KeyTransform(
self.lhs.key_name, *self.lhs.source_expressions, **self.lhs.extra
)
key_sql, key_params = self.process_lhs(
compiler, connection, lhs=key_expr
)
lhs_sql, lhs_params = self.process_lhs(compiler, connection)
rhs_sql, rhs_params = self.process_rhs(compiler, connection)
sql = "(jsonb_typeof(%s) = %%s AND mod(%s::numeric, %%s) = %%s) IS %s" % (
key_sql, lhs_sql, rhs_sql
)
params = [
*key_params, 'number',
*lhs_params, 1, 0,
*rhs_params,
]
return sql, params
@KeyTransform.register_lookup
class KeyTransformIntegerGt(KeyTransformTextLookupMixin, Lookup):
lookup_name = 'int_gt'
prepare_rhs = False
def as_sql(self, compiler, connection):
lhs_sql, lhs_params = self.process_lhs(compiler, connection)
rhs_sql, rhs_params = self.process_rhs(compiler, connection)
sql = "%s::int > %s" % (lhs_sql, rhs_sql)
params = [*lhs_params, *rhs_params]
return sql, params
_
これが完了すると、次のように制約を定義できるようになります
_CheckConstraint(
check=Q(
linkage__root__in_sub_project__is_int=True,
linkage__root__in_sub_project__int_gt=0,
),
name='asp_sub_project_positive_integer',
)
_
Django 3.1になったら、output_field = models.BooleanField()
がある限り、RawSQL
を_CheckConstraint.check
_に直接渡すことができます。
_RawSQL("""
jsonb_typeof(linkage-> 'root' -> 'in_sub_project') is not distinct from 'number'
and (linkage->'root'->>'in_sub_project')::numeric % 1 = 0
and (linkage->'root'->>'in_sub_project')::numeric > 0
""",
output_field=models.BooleanField()
)
_