Skip to content

Commit

Permalink
Resolved #30969 -- Added support for query expressions as default values
Browse files Browse the repository at this point in the history
  • Loading branch information
codingjoe committed Nov 10, 2019
1 parent 85efc14 commit acb09c8
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 12 deletions.
3 changes: 2 additions & 1 deletion django/db/models/fields/__init__.py
Expand Up @@ -738,7 +738,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
Expand Down
13 changes: 13 additions & 0 deletions docs/ref/models/fields.txt
Expand Up @@ -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 </ref/models/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``
------------

Expand Down
3 changes: 3 additions & 0 deletions docs/releases/3.1.txt
Expand Up @@ -189,6 +189,9 @@ Pagination

* :class:`~django.core.paginator.Paginator` can now be iterated over to yield
its pages.
* The Oracle and PostgreSQL backends support
:doc:`Query Expressions </ref/models/expressions>` as default values for model
fields.

Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~
Expand Down
17 changes: 6 additions & 11 deletions tests/queries/models.py
Expand Up @@ -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):
Expand Down Expand Up @@ -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())
9 changes: 9 additions & 0 deletions tests/queries/test_db_returning.py
Expand Up @@ -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)

0 comments on commit acb09c8

Please sign in to comment.