英文:
Django migrate naive DateTimeField
问题
我非常难过:每次我迁移数据库时,Django都会说我太天真了:
$ python manage.py migrate
RuntimeWarning: DateTimeField Book.released收到了一个天真的日期时间(2023-02-17 22:59:29.126480),而时间区支持已激活。
...而且最糟糕的部分是:这不可能修复!
重现步骤:
$ python -V
Python 3.10.6
$ pipenv --version
pipenv,版本 2022.11.11
$ mkdir naive-django
$ cd naive-django
$ pipenv install django
$ pipenv shell
$ python -m django --version
4.1.7
$ django-admin startproject naive_project
$ cd naive_project
$ python manage.py startapp naive_app
$ vim naive_project/settings.py
...
INSTALLED_APPS = [
'naive_app.apps.NaiveAppConfig',
...
$ vim naive_app/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
$ python manage.py makemigrations
$ python manage.py migrate
到目前为止都没有问题。现在让我们添加一个DateTimeField
:
$ vim naive_app/models.py
from datetime import datetime
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
released = models.DateTimeField(default=datetime.now)
$ python manage.py makemigrations
$ python manage.py migrate
RuntimeWarning: DateTimeField Book.released收到了一个天真的日期时间(2023-02-17 22:59:29.126480),而时间区支持已激活。
哦不!我犯了一个可怕的错误!要是不是不可能修复它就好了... 不管怎样,让我们尝试一下:
$ vim naive_app/models.py
from django.utils import timezone # 使用时区而不是日期时间
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
released = models.DateTimeField(default=timezone.now) # 使用时区而不是日期时间
$ python manage.py makemigrations
$ python manage.py migrate
嘿!它成功了!它并不是不可能修复的!
让我们写一个测试:
$ vim naive_app/tests.py
from django.test import TestCase
class NaiveTests(TestCase):
def test_naive(self):
pass
$ python manage.py test
RuntimeWarning: DateTimeField Book.released收到了一个天真的日期时间(2023-02-17 23:10:54.367162),而时间区支持已激活。
哦不!它还没有修复!每次我运行测试时,都会从头开始构建数据库并执行我的旧迁移!
$ echo "请 Django 先生,我道歉。我将删除我的模型。"
$ vim naive_app/models.py
# from django.utils import timezone # 使用时区而不是日期时间
# from django.db import models
#
#
# class Book(models.Model):
# title = models.CharField(max_length=100)
# released = models.DateTimeField(default=timezone.now) # 使用时区而不是日期时间
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py test
RuntimeWarning: DateTimeField Book.released收到了一个天真的日期时间(2023-02-17 23:18:36.955394),而时间区支持已激活。
即使模型已删除,测试几乎是空的,我仍然收到警告。
你有什么想法吗?
$ exit
$ pipenv --rm
$ cd ..
$ rm -rf naive-django
英文:
I am very sad: Every time I migrate the database, Django calls me naive:
$ python manage.py migrate
RuntimeWarning: DateTimeField Book.released received a naive datetime (2023-02-17 22:59:29.126480) while time zone support is active.
...and the worst part is: It's impossible to fix it!
Steps to reproduce:
$ python -V
Python 3.10.6
$ pipenv --version
pipenv, version 2022.11.11
$ mkdir naive-django
$ cd naive-django
$ pipenv install django
$ pipenv shell
$ python -m django --version
4.1.7
$ django-admin startproject naive_project
$ cd naive_project
$ python manage.py startapp naive_app
$ vim naive_project/settings.py
...
INSTALLED_APPS = [
'naive_app.apps.NaiveAppConfig',
...
$ vim naive_app/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
$ python manage.py makemigrations
$ python manage.py migrate
No problem so far. Let's add a DateTimeField
now:
$ vim naive_app/models.py
from datetime import datetime
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
released = models.DateTimeField(default=datetime.now)
$ python manage.py makemigrations
$ python manage.py migrate
RuntimeWarning: DateTimeField Book.released received a naive datetime (2023-02-17 22:59:29.126480) while time zone support is active.
Oh no! I made a terrible mistake! If only it was not impossible to fix it... Let's try anyway:
$ vim naive_app/models.py
from django.utils import timezone # timezone instead of datetime
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
released = models.DateTimeField(default=timezone.now) # timezone instead of datetime
$ python manage.py makemigrations
$ python manage.py migrate
Hey! It worked! It was not impossible after all!
Let's write a test:
$ vim naive_app/tests.py
from django.test import TestCase
class NaiveTests(TestCase):
def test_naive(self):
pass
$ python manage.py test
RuntimeWarning: DateTimeField Book.released received a naive datetime (2023-02-17 23:10:54.367162) while time zone support is active.
Oh no! It's not fixed! Every time I run the tests, a database is built from scratch and my old migration is executed!
$ echo "Please Mister Django, I apologize. I'm going to delete my model."
$ vim naive_app/models.py
# from django.utils import timezone # timezone instead of datetime
# from django.db import models
#
#
# class Book(models.Model):
# title = models.CharField(max_length=100)
# released = models.DateTimeField(default=timezone.now) # timezone instead of datetime
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py test
RuntimeWarning: DateTimeField Book.released received a naive datetime (2023-02-17 23:18:36.955394) while time zone support is active.
I still get a warning while the model is deleted and the test is almost empty.
Would you have an idea?
$ exit
$ pipenv --rm
$ cd ..
$ rm -rf naive-django
答案1
得分: 1
如果您压缩添加DateTimeField
并修复默认值的两个迁移,它们将被优化为一个使用最新默认值的单个迁移,使用不正确默认值的旧操作将不再运行,因此您不应该收到警告。
$ python manage.py squashmigrations naive_app 0002 0003
$ python manage.py migrate
$ python manage.py test
英文:
If you squash the two migrations that add the DateTimeField
and fix the default they will be optimised into a single migration that uses the latest default, the old operation using the incorrect default will then not run so you shouldn't get the warning
$ python manage.py squashmigrations naive_app 0002 0003
$ python manage.py migrate
$ python manage.py test
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论