关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】

chatgpt说这个字段默认情况下: blank=Falsenull=False,也就是在数据库层面和表单层面都不能为空,我们不妨来测试一下在数据库层面是不是这样。
沿用博文 https://blog.csdn.net/wenhao_ir/article/details/135499962的配置。

模型代码如下:

from django.db import models


class User(models.Model):
    username = models.CharField(max_length=4)
    post_time = models.DateTimeField(verbose_name='发布时间')

    # 其他字段...

    def __str__(self):
        return self.username

在运行命令 manage.py makemigrations 时,报下面的错:

You are trying to add a non-nullable field 'post_time' to user without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option:

这个错误是由于你尝试向现有的数据库表(User模型)中添加一个非空字段(post_time字段),而该字段没有默认值。由于已有的数据库表中已经存在数据,Django 不知道如何为这个新字段提供默认值,因此它要求你在迁移过程中选择一种方式来解决这个问题。

在你的情况下,当你运行 manage.py makemigrations 时,Django 检测到你添加了一个非空字段 post_time,但没有提供默认值。现在,Django 要求你选择一种方式来处理现有的数据。

你可以选择以下其中一种选项:

  1. 提供一个一次性的默认值 (1): 选择这个选项,Django 将为已存在的行设置一个默认值。你需要输入一个合适的默认时间值,该值将被应用到所有已有的行。

  2. 退出,并允许我在 models.py 中添加默认值 (2): 选择这个选项,你将手动在 models.py 中为新字段提供默认值,然后再运行 makemigrations。这样,Django 将在生成迁移文件时使用你提供的默认值。

在你的模型中,如果你希望 post_time 字段可以为空,你可以在模型字段中添加 null=Trueblank=True,并确保你的数据库迁移文件中有这些更改。这样,Django 将允许在数据库中存储 null 值,而不需要提供默认值。

from django.db import models


class User(models.Model):
    username = models.CharField(max_length=4)
    email = models.EmailField(unique=True)
    post_time = models.DateTimeField(verbose_name='发布时间')

    # 其他字段...

    def __str__(self):
        return self.username

如果你选择提供一次性的默认值,Django 会在生成的迁移文件中为你处理这个默认值。如果选择退出并手动在 models.py 中添加默认值,你需要在模型中设置默认值,然后再运行 manage.py makemigrations

从这里就可以看出默认情况下这个的确是非空值的。出现上面的原因是我是在原有的数据库表的基础上升级数据库表,这导致原来已经存在的一些行是没有数据的。原来的表的情况如下:
关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第1张图片
在这里我们选择 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第2张图片
关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第3张图片
需要输入一个默认值作为默认值,这里就根据建议用当前时间作为默认值,所以输入:timezone.now
关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第4张图片
从这一步的操作再一次应证了DateTimeField字段默认情况下是非空的。

然后执行迁移:

manage.py migrate

关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第5张图片
此时发现之前存在的行已经被添加默认值了:
关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第6张图片
此时我们手动插入一条数据,我们首先试下在插入时对于DateTimeField字段留空,看能不能正常运行:

# 创建一个用户
user = User(username='名字02', email='[email protected]')
user.save()

关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第7张图片
可见,报错了,这里就证明了DateTimeField字段默认情况下是不能留空的。

正确的插入代码如下:

import os
import django
from django.utils import timezone

# 设置Dango运行时需要的环境变量DJANGO_SETTINGS_MODULE
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myshop.settings')

# 加载Django的设置
django.setup()

# 导入模型,注意必须在加载完Django的设置后下面的这句导入模型语句才能被正确执行
from app1.models import User

# # 清空User数据表
# User.objects.all().delete()
#
# print('Successfully written data to the database.')


time01 = timezone.datetime(2024, 1, 9, 14, 24, 23)
time01_aware = timezone.make_aware(time01)  # 添加setting.py中设置的时区信息

# 创建一个用户
user = User(username='名字06', email='[email protected]', post_time=time01_aware)
user.save()

运行效果如下:

关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第8张图片
但是这个时区是标准时区,如何设置为北京时间的时区呢?
经过我自己各种实测操作,都不行…

不过我觉得这一点对于我的网站来说并不重要,实在不行,可以把时间值取出来后,加上8个小时调整为北京时间嘛。

相关代码如下:

import os
import django
from datetime import timedelta

# 设置Dango运行时需要的环境变量DJANGO_SETTINGS_MODULE
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myshop.settings')

# 加载Django的设置
django.setup()

# 导入模型,注意必须在加载完Django的设置后下面的这句导入模型语句才能被正确执行
from app1.models import User

# # 清空User数据表
# User.objects.all().delete()
#
# print('Successfully written data to the database.')

# 查询并获取id为9的行
user_instance = User.objects.get(id=9)

# 获取post_time字段的值
post_time_value = user_instance.post_time

# 假设 post_time_value 是你从数据库中获取到的 UTC 时间
utc_time = post_time_value

# 添加8小时
beijing_time = utc_time + timedelta(hours=8)

# 打印结果或进行其他操作
print(beijing_time)

运行效果如下:
在这里插入图片描述
关于Django字段类型DateTimeField默认是不是不能为空的测试【DateTimeField学习过程记录】_第9张图片

你可能感兴趣的:(Django,django)