Can not assign None to Django DateTimeField()

Question:

Can I judge this is a bug?
DateTimeField is inherited from DateField and it can be an optional

I have read:
How to make Django's DateTimeField optional?
How can I make my model fields optional in Django?

models.py

class Circuit(SoftDeletionModel):
    ...
    created_datetime = models.DateTimeField(default=timezone.now)
    updated_datetime = models.DateTimeField(auto_now=True)
    expiry_datetime = models.DateTimeField(null=True, blank=True, default=None)

At terminal

$ python -B manage.py makemigrations --settings=config.settings.docker
apps.circuits is ready
apps.circuits_networkdevices is ready
apps.core is ready
apps.customers is ready
apps.networkdevices is ready
apps.networkscripts is ready
apps.portal is ready
apps.bod is ready
apps.scheduler is ready
You are trying to add a non-nullable field 'updated_datetime' to circuit 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)
 2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now()
>>> None
Migrations for 'circuits':
  0022_auto_20161102_1714.py:
    - Add field expiry_datetime to circuit
    - Add field updated_datetime to circuit

migration_file.py

# -*- coding: utf-8 -*-
# Generated by Django 1.9.9 on 2016-11-02 10:14
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('circuits', '0021_auto_20161102_1653'),
    ]

    operations = [
        migrations.AddField(
            model_name='circuit',
            name='expiry_datetime',
            field=models.DateTimeField(blank=True, default=None, null=True),
        ),
        migrations.AddField(
            model_name='circuit',
            name='updated_datetime',
            field=models.DateTimeField(auto_now=True, default=None),
            preserve_default=False,
        ),
    ]

Error Django:

django.db.utils.IntegrityError: column "updated_datetime" contains null values

Error Postgres:

postgres_1       | ERROR:  column "expiry_datetime" contains null values
postgres_1       | STATEMENT:  ALTER TABLE "circuits_circuit" ADD COLUMN "expiry_datetime" timestamp with time zone NOT NULL

Spec:

In [2]: django.VERSION
Out[2]: (1, 9, 9, 'final', 0)

$ python --version
Python 3.5.1

> SELECT version();
+------------------------------------------------------------------------------------------+
| version                                                                                  |
|------------------------------------------------------------------------------------------|
| PostgreSQL 9.5.3 on x86_64-pc-linux-gnu, compiled by gcc (Debian 4.9.2-10) 4.9.2, 64-bit |
+------------------------------------------------------------------------------------------+
Asked By: joe

||

Answers:

You misunderstand what auto_now does

Automatically set the field to now every time the object is saved.

You’ll still need to specify a valid default or allow for null values with null=True

Answered By: Sayse

You cannot assign None to updated_datetime because you have not set null=True in the model.

You have created a migration that tells django what to do if it encounters existing rows in the circuit table when adding the field but that is not the same as being able to do it.

The default value asked for by the migration does not check that value is allowed to be used, it’s trusting you to know what you are doing.

In your migration use datetime.now() rather than None.

Answered By: Tony

DateField.auto_now

Automatically set the field to now every time the object is saved.

DateField.auto_now_add

Automatically set the field to now when the object is first created.

You can use anyone:

created_date = models.DateTimeField(auto_now_add=True, null=True)

or

created_date = models.DateTimeField(null=True)

or

from django.utils import timezone
created_date = models.DateTimeField(default=timezone.now)
Answered By: Khabir
  1. You have to delete all migrations and erase your database data too and do migrations again

  2. excute commands:

python manage.py makemigrations
python manage.py migrate --fake
Answered By: Ershan
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.