通过 Django 创建数据库约束
Create DB Constraint via Django
我有一个看起来像这样的 Django 模型:
class Dummy(models.Model):
...
system = models.CharField(max_length=16)
我希望system
永远不会为空或包含空格。
我知道如何在 Django 中使用验证器。
但我会在数据库级别强制执行此操作。
为此创建数据库约束的最简单且类似于 django 的方法是什么?
我使用 PostgreSQL,不需要支持任何其他数据库。
我修改了我的答案以满足您的要求。
因此,如果您想 运行 数据库约束,请尝试这个:
import psycopg2
def your_validator():
conn = psycopg2.connect("dbname=YOURDB user=YOURUSER")
cursor = conn.cursor()
query_result = cursor.execute("YOUR QUERY")
if query_result is Null:
# Do stuff
else:
# Other Stuff
然后使用pre_save
信号。
在您的 models.py
文件中添加
from django.db.models.signals import pre_save
class Dummy(models.Model):
...
@staticmethod
def pre_save(sender, instance, *args, **kwargs)
# Of course, feel free to parse args in your def.
your_validator()
第一期:通过Django创建数据库约束
一个)
似乎 django 还没有内置此功能。有一个 9 岁的开放 ticket,但我不会为已经持续了这么长时间的事情屏住呼吸。
编辑:从 2.2 版(2019 年 4 月)开始,Django 支持数据库级别 check constraints。
B) 您可以查看包 django-db-constraints,通过它您可以在模型 Meta
中定义约束。我没有测试这个包,所以我不知道它到底有多好用。
# example using this package
class Meta:
db_constraints = {
'price_above_zero': 'check (price > 0)',
}
第二期: 字段 system
不应为空,也不应包含空格
现在我们需要在 postgres
语法中构建 check
约束来完成它。我想到了这些选项:
去掉空格后检查system
的长度是否不同。使用来自 this answer 的想法,您可以尝试:
/* this check should only pass if `system` contains no
* whitespaces (`\s` also detects new lines)
*/
check ( length(system) = length(regexp_replace(system, '\s', '', 'g')) )
检查空格计数是否为 0。为此,您可以使用 regexp_matches
:
/* this check should only pass if `system` contains no
* whitespaces (`\s` also detects new lines)
*/
check ( length(regexp_matches(system, '\s', 'g')) = 0 )
注意 length
函数 不能 与 regexp_matches
一起使用,因为后者 returns 一个 set of text[]
(一组数组),但我现在找不到合适的函数来计算该集合的元素。
最后,将前两期放在一起,您的方法可能如下所示:
class Dummy(models.Model):
# this already sets NOT NULL to the field in the database
system = models.CharField(max_length=16)
class Meta:
db_constraints = {
'system_no_spaces': 'check ( length(system) > 0 AND length(system) = length(regexp_replace(system, "\s", "", "g")) )',
}
这会检查字段值:
- 不包含NULL(
CharField
默认添加NOT NULL
约束)
- 不为空(
check
第一部分:length(system) > 0
)
- 没有空格(
check
的第二部分:替换空格后长度相同)
让我知道您的效果如何,或者这种方法是否存在问题或缺点。
您可以通过自定义 Django 迁移添加 CHECK
约束。要检查字符串长度,您可以使用 char_length
函数和 position
检查是否包含空格。
引用自 postgres 文档 (https://www.postgresql.org/docs/current/static/ddl-constraints.html):
A check constraint is the most generic constraint type. It allows you
to specify that the value in a certain column must satisfy a Boolean
(truth-value) expression.
到运行任意sql迁移RunSQL
操作可以使用(https://docs.djangoproject.com/en/2.0/ref/migration-operations/#runsql):
Allows running of arbitrary SQL on the database - useful for more
advanced features of database backends that Django doesn’t support
directly, like partial indexes.
创建空迁移:
python manage.py makemigrations --empty yourappname
添加sql创建约束:
# Generated by Django A.B on YYYY-MM-DD HH:MM
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunSQL('ALTER TABLE appname_dummy ADD CONSTRAINT syslen '
'CHECK (char_length(trim(system)) > 1);',
'ALTER TABLE appname_dummy DROP CONSTRAINT syslen;'),
migrations.RunSQL('ALTER TABLE appname_dummy ADD CONSTRAINT syswh '
'CHECK (position(' ' in trim(system)) = 0);',
'ALTER TABLE appname_dummy DROP CONSTRAINT syswh;')
]
运行 迁移:
python manage.py migrate yourappname
2019 年更新
Django 2.2 添加了对 database-level constrains. The new CheckConstraint and UniqueConstraint classes enable adding custom database constraints. Constraints are added to models using the Meta.constraints option.
的支持
您的系统验证看起来像这样:
from django.db import models
from django.db.models.constraints import CheckConstraint
from django.db.models.query_utils import Q
class Dummy(models.Model):
...
system = models.CharField(max_length=16)
class Meta:
constraints = [
CheckConstraint(
check=~Q(system="") & ~Q(system__contains=" "),
name="system_not_blank")
]
我有一个看起来像这样的 Django 模型:
class Dummy(models.Model):
...
system = models.CharField(max_length=16)
我希望system
永远不会为空或包含空格。
我知道如何在 Django 中使用验证器。
但我会在数据库级别强制执行此操作。
为此创建数据库约束的最简单且类似于 django 的方法是什么?
我使用 PostgreSQL,不需要支持任何其他数据库。
我修改了我的答案以满足您的要求。
因此,如果您想 运行 数据库约束,请尝试这个:
import psycopg2
def your_validator():
conn = psycopg2.connect("dbname=YOURDB user=YOURUSER")
cursor = conn.cursor()
query_result = cursor.execute("YOUR QUERY")
if query_result is Null:
# Do stuff
else:
# Other Stuff
然后使用pre_save
信号。
在您的 models.py
文件中添加
from django.db.models.signals import pre_save
class Dummy(models.Model):
...
@staticmethod
def pre_save(sender, instance, *args, **kwargs)
# Of course, feel free to parse args in your def.
your_validator()
第一期:通过Django创建数据库约束
一个)
似乎 django 还没有内置此功能。有一个 9 岁的开放 ticket,但我不会为已经持续了这么长时间的事情屏住呼吸。
编辑:从 2.2 版(2019 年 4 月)开始,Django 支持数据库级别 check constraints。
B) 您可以查看包 django-db-constraints,通过它您可以在模型 Meta
中定义约束。我没有测试这个包,所以我不知道它到底有多好用。
# example using this package
class Meta:
db_constraints = {
'price_above_zero': 'check (price > 0)',
}
第二期: 字段 system
不应为空,也不应包含空格
现在我们需要在 postgres
语法中构建 check
约束来完成它。我想到了这些选项:
去掉空格后检查
system
的长度是否不同。使用来自 this answer 的想法,您可以尝试:/* this check should only pass if `system` contains no * whitespaces (`\s` also detects new lines) */ check ( length(system) = length(regexp_replace(system, '\s', '', 'g')) )
检查空格计数是否为 0。为此,您可以使用
regexp_matches
:/* this check should only pass if `system` contains no * whitespaces (`\s` also detects new lines) */ check ( length(regexp_matches(system, '\s', 'g')) = 0 )
注意
length
函数 不能 与regexp_matches
一起使用,因为后者 returns 一个set of text[]
(一组数组),但我现在找不到合适的函数来计算该集合的元素。
最后,将前两期放在一起,您的方法可能如下所示:
class Dummy(models.Model):
# this already sets NOT NULL to the field in the database
system = models.CharField(max_length=16)
class Meta:
db_constraints = {
'system_no_spaces': 'check ( length(system) > 0 AND length(system) = length(regexp_replace(system, "\s", "", "g")) )',
}
这会检查字段值:
- 不包含NULL(
CharField
默认添加NOT NULL
约束) - 不为空(
check
第一部分:length(system) > 0
) - 没有空格(
check
的第二部分:替换空格后长度相同)
让我知道您的效果如何,或者这种方法是否存在问题或缺点。
您可以通过自定义 Django 迁移添加 CHECK
约束。要检查字符串长度,您可以使用 char_length
函数和 position
检查是否包含空格。
引用自 postgres 文档 (https://www.postgresql.org/docs/current/static/ddl-constraints.html):
A check constraint is the most generic constraint type. It allows you to specify that the value in a certain column must satisfy a Boolean (truth-value) expression.
到运行任意sql迁移RunSQL
操作可以使用(https://docs.djangoproject.com/en/2.0/ref/migration-operations/#runsql):
Allows running of arbitrary SQL on the database - useful for more advanced features of database backends that Django doesn’t support directly, like partial indexes.
创建空迁移:
python manage.py makemigrations --empty yourappname
添加sql创建约束:
# Generated by Django A.B on YYYY-MM-DD HH:MM
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunSQL('ALTER TABLE appname_dummy ADD CONSTRAINT syslen '
'CHECK (char_length(trim(system)) > 1);',
'ALTER TABLE appname_dummy DROP CONSTRAINT syslen;'),
migrations.RunSQL('ALTER TABLE appname_dummy ADD CONSTRAINT syswh '
'CHECK (position(' ' in trim(system)) = 0);',
'ALTER TABLE appname_dummy DROP CONSTRAINT syswh;')
]
运行 迁移:
python manage.py migrate yourappname
2019 年更新
Django 2.2 添加了对 database-level constrains. The new CheckConstraint and UniqueConstraint classes enable adding custom database constraints. Constraints are added to models using the Meta.constraints option.
的支持您的系统验证看起来像这样:
from django.db import models
from django.db.models.constraints import CheckConstraint
from django.db.models.query_utils import Q
class Dummy(models.Model):
...
system = models.CharField(max_length=16)
class Meta:
constraints = [
CheckConstraint(
check=~Q(system="") & ~Q(system__contains=" "),
name="system_not_blank")
]