在Django中,null=True和blank=True有什么区别?

1364

当我们在Django中添加模型字段时,通常会写成:

models.CharField(max_length=100, null=True, blank=True)

对于ForeignKeyDecimalField等字段也是如此操作。以下是关于在不同的(CharField, ForeignKey, ManyToManyField, DateTimeField)字段中应用:

  1. null=True仅针对
  2. blank=True仅针对
  3. null=Trueblank=True

有什么区别?使用选项1、2或3的优点和缺点是什么?


20
这里有关于这个问题的好回答:https://dev59.com/tWsz5IYBdhLWcg3wBzbi 和 https://dev59.com/_2855IYBdhLWcg3wXTAI。 - juliomalegria
6
好的阅读材料:http://www.b-list.org/weblog/2006/jun/28/django-tips-difference-between-blank-and-null/这篇文章讨论了在Django模型中使用"blank"和"null"选项的区别。简单来说,"blank"是用于验证表单数据的,而"null"是用于数据库存储的。如果一个字段可以为空,则应该将"blank"设置为True,并且如果该字段与数据库的NULL值相关联,则应该将"null"设置为True。此外,作者还讨论了一些关于如何正确使用这些选项的技巧和陷阱。 - salmatron
是的,我也有这样一个ForeignKey的应用场景,其中blank=True,但没有null=True。当保存模型时,我想通过创建已发布的条目来自动“发布”它。因此,我不能将null保存到数据库中,因为每个模型都必须是"published",但我希望能够在管理页面中留空该字段。 - Sergey Orshanskiy
1
我认为你可能会对将空的可空CharField保存为null而不是空字符串感兴趣。关于这个问题有很多讨论,你可能会遇到一个非常实际的问题(例如,你想为每个用户添加一个可以为空且应该是唯一的openid url)。 - ramwin
避免在CharField和TextField等基于字符串的字段上使用null。https://docs.djangoproject.com/en/3.1/ref/models/fields/ - Fernando Valente
28个回答

1591

null=True会在数据库中的列上设置NULL(而不是NOT NULL)。像DateTimeFieldForeignKey这样的Django字段类型的空值将存储为NULL

blank决定了表单中该字段是否是必填项。包括管理页面和自定义表单。如果blank=True,则该字段不是必填项,而如果False,则该字段不能为空。

这两个结合起来使用频率很高,因为通常如果你要允许表单中的字段为空,你也需要让你的数据库允许该字段的NULL值。例外情况是CharFieldTextField,在Django中它们永远不会保存为NULL。空值会以空字符串('')的形式存储在数据库中。

以下是一些示例:

models.DateTimeField(blank=True) # raises IntegrityError if blank

models.DateTimeField(null=True) # NULL allowed, but must be filled out in a form

显然,这两个选项不具有逻辑意义(尽管如果您希望在表单中始终需要字段,在通过类似于shell的方式处理对象时可选,则可能存在对null=True, blank=False的使用情况)。

models.CharField(blank=True) # No problem, blank is stored as ''

models.CharField(null=True) # NULL allowed, but will never be set as NULL

CHARTEXT类型在Django中不会被保存为NULL,因此null=True是不必要的。但是,您可以手动将其中一个字段设置为None以强制将其设置为NULL。如果您有可能需要这样做的情况,则仍应包括null=True


12
当Django尝试将记录保存到数据库时,如果字段不需要用户填写但在数据库级别上不为null,则会引发IntegrityError。 - Chris Pratt
3
我认为用户798719指的是空白值的取值,在你的例子中应该为False而不是True:models.DateTimeField(blank=False) # 如果为空,会引发完整性错误。 - Joseph Sheedy
5
不,Chris 的意思是指出在 DateTimeField 中有 blank=True 而没有 null=True 会引起问题。需要注意的是,在翻译过程中不能改变原文的意思,并且不提供任何解释或额外的内容。 - Vinod Kurup
7
注意给Oracle用户:在Django中,“CHARTEXT永远不会被保存为NULL”这句话不是真的。虽然这对于大多数后端是正确的,但是对于Oracle来说,它会强制将空字符串变成NULL。因此,Django的Oracle后端是上述语句的一个例外。Django文档 - stvsmth
9
有人会提到这个组合吗:blank=Truenull=Falsedefault="something" - Brian H.
显示剩余7条评论

169

这是ORM如何为Django 1.8映射blanknull字段的方式。

class Test(models.Model):
    charNull        = models.CharField(max_length=10, null=True)
    charBlank       = models.CharField(max_length=10, blank=True)
    charNullBlank   = models.CharField(max_length=10, null=True, blank=True)

    intNull         = models.IntegerField(null=True)
    intBlank        = models.IntegerField(blank=True)
    intNullBlank    = models.IntegerField(null=True, blank=True)

    dateNull        = models.DateTimeField(null=True)
    dateBlank       = models.DateTimeField(blank=True)
    dateNullBlank   = models.DateTimeField(null=True, blank=True)        

创建的数据库字段适用于PostgreSQL 9.4

CREATE TABLE Test (
  id              serial                    NOT NULL,

  "charNull"      character varying(10),
  "charBlank"     character varying(10)     NOT NULL,
  "charNullBlank" character varying(10),

  "intNull"       integer,
  "intBlank"      integer                   NOT NULL,
  "intNullBlank"  integer,

  "dateNull"      timestamp with time zone,
  "dateBlank"     timestamp with time zone  NOT NULL,
  "dateNullBlank" timestamp with time zone,
  CONSTRAINT Test_pkey PRIMARY KEY (id)
)

创建于MySQL 5.6的数据库字段如下:

CREATE TABLE Test (
     `id`            INT(11)     NOT  NULL    AUTO_INCREMENT,

     `charNull`      VARCHAR(10) NULL DEFAULT NULL,
     `charBlank`     VARCHAR(10) NOT  NULL,
     `charNullBlank` VARCHAR(10) NULL DEFAULT NULL,

     `intNull`       INT(11)     NULL DEFAULT NULL,
     `intBlank`      INT(11)     NOT  NULL,
     `intNullBlank`  INT(11)     NULL DEFAULT NULL,

     `dateNull`      DATETIME    NULL DEFAULT NULL,
     `dateBlank`     DATETIME    NOT  NULL,
     `dateNullBlank` DATETIME    NULL DEFAULT NULL
)

72
换句话说,空白对数据库没有影响,而空值(null)控制数据库列是否允许为空值。这个答案说法有点冗长,对于空白没有提供任何有用信息。 - Carl Meyer
26
@CarlMeyer: 我想看看它如何映射到数据库中,并分享,因为这会为其他人节省时间。在吸收和记忆方面,理论与实例的区别很大。事实上,我特意为一个我没有使用的数据库添加了映射。感谢你的反对投票。显然有很多人发现这很有用,他们不同意你的看法。 - user
8
如果您从所呈现的数据中得出一些总结性结论,那么这可能是一个有用的答案,但我不认为呈现原始数据转储是一个有用的答案。在这种情况下,它实际上是一个具有误导性的答案,因为(没有进一步的评论)它暗示着blanknull的影响应该反映在数据库列中,而事实上blank只影响了Python处理,而不是数据库列。如果其他人发现它有用,他们可以点赞;对于那些被误导的人来说,他们可能会_认为_它是有用的。 - Carl Meyer
8
接受的答案已经有近3年的时间了,详细解释了一切。在此重复相同的信息毫无意义。 - user

151
重要的是要了解 Django 模型字段定义中的选项(至少)有两个作用:定义数据库表和定义模型表单的默认格式和验证。 (我说“默认”是因为值始终可以通过提供自定义表单来覆盖。)一些选项影响数据库,一些选项影响表单,而一些选项则影响两者。
当涉及到 null 和 blank 时,其他答案已经明确表示前者影响数据库表定义,后者影响模型验证。 我认为可以通过查看所有四种可能配置的用例来更清楚地区分它们。
  • null=Falseblank=False:这是默认配置,意味着该值在所有情况下都是必需的。

  • null=Trueblank=True:这意味着该字段在所有情况下都是可选的。但是,如下所述,这不是使基于字符串的字段可选的推荐方式。

  • null=Falseblank=True:这意味着表单不需要一个值,但数据库需要。有许多用例:

    • 最常见的用法是可选的基于字符串的字段。如文档中所述,Django 的惯用语是使用空字符串表示缺失值。如果也允许 NULL,则会出现两种不同的表示缺失值的方式。(但是,如果该字段还是 unique,则必须使用 null=True 来防止多个空字符串导致唯一性检查失败。)

    • 另一个常见情况是您想根据另一个字段的值自动计算一个字段(例如在您的 save() 方法中)。您不希望用户在表单中提供该值(因此 blank=True),但您确实希望数据库强制始终提供值(null=False)。

    • 另一个用法是当您想指示 ManyToManyField 是可选的时。因为该字段是作为一个单独的表而不是数据库列实现的,所以 null 是没有意义的。但是,blank 的值仍会影响表单,控制在没有关系时是否验证将成功。

  • null=Trueblank=False:这意味着表单需要一个值,但数据库不需要。这可能是最少使用的配置,但有一些用例:

    • 即使业务逻辑实际上不需要,也完全可以要求用户始终包括一个值。毕竟,表单只是添加和编辑数据的一种方式。您可能有代码正在生成不需要与人类编辑器要求相同的严格验证的数据。

    • 我看到的另一个用例是当您有一个不希望允许级联删除ForeignKey 时。也就是说,在正常使用中,关系应始终存在(blank=False),但如果它指向的对象恰好被删除,则不希望删除此对象。在这种情况下,您可以使用 null=Trueon_delete=models.SET_NULL 实现一种简单的 软删除


8
这是一个完美的答案,所有可能的组合都用非常简洁的方式解释了! - ruslaniv

70

您可能已经得到了答案,但直到今天仍然很难判断在字段中是应该放置null=True还是blank=True,或者两者都放置。我个人认为向开发人员提供如此多的选项非常没有用和令人困惑。让他们自己处理nulls或blanks。

我遵循这张表格,来自 Two Scoops of Django enter image description here

Table showing when to use null or blank for each field type


4
FYI,“NullBooleanField” 自 Django 3.1 起已被弃用,应使用“BooleanField(null=True)”代替:https://docs.djangoproject.com/en/3.1/ref/models/fields/#nullbooleanfield - Michael Hays

61
根据 Django Model Field 参考文档(链接):

字段选项

以下参数适用于所有字段类型。所有参数都是可选的。


null

Field.null

如果设置为 True,Django 将会在数据库中将空白值存储为 NULL。默认设置为 False

避免在基于字符串的字段(例如 CharFieldTextField)上使用 null,因为空字符串值将始终存储为空字符串,而不是 NULL。如果一个基于字符串的字段具有 null=True,那么它就有两个可能的“没有数据”的值: NULL 和空字符串。在大多数情况下,拥有两个“无数据”可能的值是多余的;Django 约定使用空字符串而不是 NULL

对于基于字符串和非基于字符串的字段,如果您希望在表单中允许空值,则还需要设置 blank=True,因为 null 参数仅影响数据库存储(请参见 blank)。

注意

当使用 Oracle 数据库后端时,无论此属性如何,空字符串的值将被存储为 NULL。


blank

Field.blank

如果设置为 True,该字段允许为空白。默认设置为 False

请注意,这与 null 是不同的。 null 纯粹表示数据库中的空值,而 blank 则表示表单中可以为空。

与数据库相关的内容使用,而blank与验证有关。如果一个字段具有blank=True,表单验证将允许输入空值。如果一个字段具有blank=False,则该字段是必填的。


34

简而言之,null=True 表示数据库可以接受 NULL 值;而 blank=True 表示在表单验证时该字段是否可接受空值(如果 blank=True,则该字段可以为空,如果 blank=False [默认值],则在表单验证时它将显示错误信息此字段是必需的)。

null=True/False 与数据库有关

blank=True/False 与表单验证有关


23

这里是一个字段的例子,它使用了blank=Truenull=True

description = models.TextField(blank=True, null= True)
在这种情况下:blank = True:告诉我们的表单可以将描述字段留空而不会报错;null = True:告诉我们的数据库可以在数据库字段中记录空值而不会报错。

12
如果你设置了null=True,那么数据库列的值就可以被设置为NULL。如果你只设置了blank=True,Django会将该列的默认新值设置为""
即使是在CharFieldTextField上,也有一个情况需要使用null=True,那就是当数据库为该列设置了unique标志时。在这种情况下,你需要使用以下代码:
a_unique_string = models.CharField(blank=True, null=True, unique=True)

最好在非唯一的CharFieldTextField中跳过null=True。否则,某些字段将被设置为NULL,而其他字段将被设置为空字符串"",您将不得不每次检查字段值是否为NULL


3
令人惊讶的是,唯一一个正确理解 NULL 为何重要的答案。 - user1600649

9

nullblank的默认值为False

null:与数据库相关。定义给定数据库列是否接受空值。

blank:与验证相关。在调用form.is_valid()时,将在表单验证期间使用。

也就是说,拥有null=Trueblank=False的字段是完全可以的。这意味着在数据库级别上,该字段可以是NULL,但在应用程序级别上它是一个必填字段。

现在,大多数开发人员犯的错误在于:对于像CharFieldTextField这样的字符串字段,定义null=True。避免这样做。否则,你会得到两个可能的“无数据”值,即:None和空字符串。有两个可能的“无数据”值是冗余的。Django约定使用空字符串而不是NULL


8
null = True

这意味着数据库中没有对字段填充的限制,因此您可以拥有一个具有此选项的空值对象。

blank = True

在Django表单中,没有验证约束。因此,当您填写此模型的modelForm时,您可以将具有此选项的字段留空。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接