通过Django创建数据库约束

问题描述 投票:7回答:3

我有一个看起来像这样的Django模型:

class Dummy(models.Model):
    ...
    system = models.CharField(max_length=16)

我希望system永远不会是空的或包含空格。

我知道如何在Django中使用验证器。

但我会在数据库级别强制执行此操作。

为此创建数据库约束的最简单和类似django的方法是什么?

我使用PostgreSQL,不需要支持任何其他数据库。

django postgresql check-constraints
3个回答
9
投票

第一个问题:通过Django创建数据库约束

似乎django还没有这种能力。有一个9岁的开放ticket它,但我不会屏住呼吸这个长期的事情。

您可以查看包django-db-constraints,通过它可以在模型Meta中定义约束。我没有测试这个软件包,所以我不知道它真的有用。

# example using this package
class Meta:
    db_constraints = {
        'price_above_zero': 'check (price > 0)',
    }

第二个问题:字段system永远不应该是空的,也不应该包含空格

现在我们需要在check语法中构建postgres约束来实现这一点。我想出了这些选择:

  1. 删除空格后检查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')) )
  2. 检查空白数是否为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一起使用,因为后者返回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")) )',
        }

这将检查字段值:

  1. 不包含NULL(CharField默认添加NOT NULL约束)
  2. 不是空的(check的第一部分:length(system) > 0
  3. 没有空格(check的第二部分:替换空格后的相同长度)

让我知道这对您有何影响,或者这种方法是否有问题或缺点。


编辑:从2.2版本开始,Django拥有数据库级别的CheckConstraint


7
投票

您可以通过自定义django迁移添加CHECK约束。要检查字符串长度,可以使用char_length函数和position来检查包含的空格。

来自postgres docs(https://www.postgresql.org/docs/current/static/ddl-constraints.html)的报价:

检查约束是最通用的约束类型。它允许您指定某列中的值必须满足布尔(真值)表达式。

要在迁移中运行任意sql,可以使用qazxsw poi操作(qazxsw poi):

允许在数据库上运行任意SQL - 对于Django不直接支持的数据库后端的更高级功能(如部分索引)非常有用。

创建空迁移:

RunSQL

添加sql以创建约束:

https://docs.djangoproject.com/en/2.0/ref/migration-operations/#runsql

运行迁移:

python manage.py makemigrations --empty yourappname

5
投票

2019 Update

Django 2.2增加了对# 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 database-level constrains类可以添加自定义数据库约束。使用CheckConstraint将约束添加到模型中。

您的系统验证看起来像这样:

UniqueConstraint

1
投票

我修改我的答案以达到你的要求。

因此,如果您想运行数据库约束,请尝试以下方法:

Meta.constraints option

然后使用class Dummy(models.Model): ... system = models.CharField(max_length=16) class Meta: constraints = [ CheckConstraint( check=~Q(system="") & ~Q(system__contains=" "), name="system_not_blank") ] 信号。

在你的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
© www.soinside.com 2019 - 2024. All rights reserved.