Django 迁移普通的 DateTimeField

huangapple go评论61阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年2月18日 07:59:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/75490265.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定