You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django+Postgres测试时Slug字段触发非空约束错误问题

解决Django Slug字段测试时的非空约束问题

问题背景

我定义了这样的Django Job模型:

class Job(models.Model):
    # 其他字段
    slug = models.SlugField(verbose_name=_('slug'), max_length=151, null=True, blank=True)
    def get_absolute_url(self):
        return reverse('jobs', kwargs={'slug': self.slug})

Slug字段明明设置了允许空值,在Shell里创建实例完全正常:

In [1]: j = Job.objects.create(title='my faked title',date_start=aware_start, date_end=aware_end, amount_to_pay=10, email='fake@gmail.com')
In [2]: j
Out[2]: <Job: my faked title>

但在测试用例里创建实例却直接报错,测试代码是这样的:

class JobCreationTest(TestCase):
    def test_simple_creation(self):
        import datetime
        import pytz
        aware_start = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC)
        aware_end = datetime.datetime(2012, 8, 15, 8, 15, 12, 0, pytz.UTC)
        Job.objects.create(title='my faked title',date_start=aware_start, date_end=aware_end, amount_to_pay=10, email='fake@gmail.com')

报错信息如下:

django.db.utils.IntegrityError: null value in column 'slug' violates not-null constraint
DETAIL: Failing row contains (e814e054-e273-4316-b670-f39584f0b3ef, 2019-03-19 09:39:31.031514+00, null, 2019-03-19 09:39:31.031566+00, null, f, my faked title, fake@gmail.com, , null, null, null, null, null, null, null, null, 2011-08-15 08:15:12+00, 2012-08-15 08:15:12+00, null, null, null, , , 10, null).

我尝试过执行迁移命令,但没有效果:

$ ./manage.py makemigrations posts
No changes detected in app 'posts'
$ ./manage.py migrate posts
No migrations to apply.

去psql里查看表定义,slug字段确实是允许为空的:

\d+ posts_job
Table "public.posts_job"
Column | Type | Collation | Nullable |
----------------------+--------------------------+-----------+----------+-
id | uuid | | not null |
title | character varying(128) | | not null |
email | character varying(254) | | not null |
slug | character varying(151) | | |

问题分析

从数据库表定义来看,slug字段的Nullable列是空的,说明数据库层面确实允许空值,但测试环境却抛出了非空约束错误,大概率是测试用的临时数据库没有正确应用迁移——Django运行测试时会自动创建一个临时数据库,如果迁移文件有问题或者测试启动时迁移没有正确执行,就会出现这种模型定义和数据库结构不一致的情况。

解决方案

这里有几个可以尝试的解决步骤:

  • 强制测试环境重新应用迁移:可以运行测试时加上--keepdb参数先清空测试数据库,再重新创建:

    ./manage.py test --keepdb posts.tests.JobCreationTest
    

    如果还是不行,直接删除测试数据库(比如postgres里的test_xxx库),再重新运行测试。

  • 重新生成迁移文件:有时候迁移文件会和模型定义不同步,哪怕makemigrations提示没有变化。可以先删除posts/migrations/下除了__init__.py之外的所有文件,然后重新生成并应用迁移:

    rm posts/migrations/0*.py
    ./manage.py makemigrations posts
    ./manage.py migrate posts
    

    之后再运行测试,看看问题是否解决。

  • 显式设置slug为None:在测试用例创建实例时,手动指定slug=None,确认是否还会报错:

    Job.objects.create(
        title='my faked title',
        date_start=aware_start, 
        date_end=aware_end, 
        amount_to_pay=10, 
        email='fake@gmail.com',
        slug=None
    )
    

    如果这样不报错,说明测试环境的某个前置操作可能意外修改了slug字段的约束。

  • 检查测试数据库配置:确保settings.py里的TEST数据库配置和主数据库一致,比如是否用了不同的引擎,或者有特殊的约束设置。

内容的提问来源于stack exchange,提问作者Gonzalo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:39:34