diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index d610dc86f01a8..ecbbb39960ff5 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -737,7 +737,8 @@ def db_returning(self): Private API intended only to be used by Django itself. Currently only the PostgreSQL backend supports returning multiple fields on a model. """ - return False + from django.db.models.expressions import BaseExpression + return self.has_default() and isinstance(self.default, BaseExpression) def set_attributes_from_name(self, name): self.name = self.name or name diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index dfd9f9b665eef..660724bb6477b 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -364,6 +364,19 @@ The default value is used when new model instances are created and a value isn't provided for the field. When the field is a primary key, the default is also used when the field is set to ``None``. +.. versionadded:: 3.1 + +The Oracle and PostgreSQL database backends support +:doc:`Query Expressions ` as ``default`` values:: + + from django.db import models + from django.db.models.functions import ExtractYear, Now, Pi + + class CreatedModel(models.Model) + created = models.DateTimeField(editable=False, default=Now()) + pi = models.FloatField(default=Pi()) + year = models.PositiveSmallIntegerField(default=ExtractYear(Now())) + ``editable`` ------------ diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index 3a9381626bca3..6e1a8dfaaa46d 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -160,7 +160,9 @@ Migrations Models ~~~~~~ -* ... +* The Oracle and PostgreSQL backends support + :doc:`Query Expressions ` as default values for model + fields. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/queries/models.py b/tests/queries/models.py index e9eec5718dde8..65298d44cfcfc 100644 --- a/tests/queries/models.py +++ b/tests/queries/models.py @@ -4,7 +4,7 @@ import threading from django.db import models -from django.db.models.functions import Now +from django.db.models.functions import ExtractYear, Now, Pi class DumbCategory(models.Model): @@ -733,17 +733,12 @@ class CustomDbColumn(models.Model): ip_address = models.GenericIPAddressField(null=True) -class CreatedField(models.DateTimeField): - db_returning = True - - def __init__(self, *args, **kwargs): - kwargs.setdefault('default', Now) - super().__init__(*args, **kwargs) - - class ReturningModel(models.Model): - created = CreatedField(editable=False) + created = models.DateTimeField(editable=False, default=Now()) + created_date = models.DateTimeField(default=Now()) + year = models.PositiveSmallIntegerField(default=ExtractYear(Now())) + pi = models.FloatField(default=Pi()) class NonIntegerPKReturningModel(models.Model): - created = CreatedField(editable=False, primary_key=True) + created = models.DateTimeField(editable=False, primary_key=True, default=Now()) diff --git a/tests/queries/test_db_returning.py b/tests/queries/test_db_returning.py index 9ba352a7ab7f6..dd10b93176b2d 100644 --- a/tests/queries/test_db_returning.py +++ b/tests/queries/test_db_returning.py @@ -49,3 +49,12 @@ def test_bulk_insert(self): with self.subTest(obj=obj): self.assertTrue(obj.pk) self.assertIsInstance(obj.created, datetime.datetime) + + +@skipUnlessDBFeature('can_return_columns_from_insert') +class DatabaseDefaultsTests(TestCase): + def test_now(self): + obj = ReturningModel.objects.create() + self.assertIsInstance(obj.created, datetime.datetime) + self.assertIsInstance(obj.year, int) + self.assertEquals(obj.pi, 3.14159265358979)