From 23048d186ce0041654a9f547fe3e7177efce3076 Mon Sep 17 00:00:00 2001 From: Adam Chainz Date: Fri, 29 May 2015 15:54:10 +0100 Subject: [PATCH] Fixed #24866 -- Added Now() database function --- django/db/models/functions.py | 18 ++++++++++- docs/ref/models/database-functions.txt | 15 ++++++++++ docs/releases/1.9.txt | 3 ++ tests/db_functions/tests.py | 41 +++++++++++++++++++++++++- 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/django/db/models/functions.py b/django/db/models/functions.py index 613d396093..a39864e4b5 100644 --- a/django/db/models/functions.py +++ b/django/db/models/functions.py @@ -1,7 +1,7 @@ """ Classes that represent database functions. """ -from django.db.models import IntegerField +from django.db.models import DateTimeField, IntegerField from django.db.models.expressions import Func, Value @@ -103,6 +103,22 @@ class Lower(Func): super(Lower, self).__init__(expression, **extra) +class Now(Func): + template = 'CURRENT_TIMESTAMP' + + def __init__(self, output_field=None, **extra): + if output_field is None: + output_field = DateTimeField() + super(Now, self).__init__(output_field=output_field, **extra) + + def as_postgresql(self, compiler, connection): + # Postgres' CURRENT_TIMESTAMP means "the time at the start of the + # transaction". We use STATEMENT_TIMESTAMP to be cross-compatible with + # other databases. + self.template = 'STATEMENT_TIMESTAMP()' + return self.as_sql(compiler, connection) + + class Substr(Func): function = 'SUBSTRING' diff --git a/docs/ref/models/database-functions.txt b/docs/ref/models/database-functions.txt index cdd46ff1a2..b797e5f1df 100644 --- a/docs/ref/models/database-functions.txt +++ b/docs/ref/models/database-functions.txt @@ -117,6 +117,21 @@ Usage example:: >>> print(author.name_lower) margaret smith +Now +--- + +.. class:: Now() + +.. versionadded:: 1.9 + +Returns the database server's current date and time when the query is executed. + +Usage example:: + + >>> from django.db.models.functions import Now + >>> Article.objects.filter(published__lte=Now()) + [] + Substr ------ diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index bca086b207..192da111c2 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -240,6 +240,9 @@ Models * Added the :lookup:`date` lookup to :class:`~django.db.models.DateTimeField` to allow querying the field by only the date portion. +* Added the :class:`~django.db.models.functions.Now` database function, which + returns the current date and time. + CSRF ^^^^ diff --git a/tests/db_functions/tests.py b/tests/db_functions/tests.py index f07e8770f0..1df9800f13 100644 --- a/tests/db_functions/tests.py +++ b/tests/db_functions/tests.py @@ -1,8 +1,10 @@ from __future__ import unicode_literals +from datetime import datetime, timedelta + from django.db.models import CharField, TextField, Value as V from django.db.models.functions import ( - Coalesce, Concat, Length, Lower, Substr, Upper, + Coalesce, Concat, Length, Lower, Now, Substr, Upper, ) from django.test import TestCase from django.utils import six, timezone @@ -311,3 +313,40 @@ class FunctionTests(TestCase): ], lambda a: a.name ) + + def test_now(self): + ar1 = Article.objects.create( + title='How to Django', + text=lorem_ipsum, + written=timezone.now(), + ) + ar2 = Article.objects.create( + title='How to Time Travel', + text=lorem_ipsum, + written=timezone.now(), + ) + + num_updated = Article.objects.filter(id=ar1.id, published=None).update(published=Now()) + self.assertEqual(num_updated, 1) + + num_updated = Article.objects.filter(id=ar1.id, published=None).update(published=Now()) + self.assertEqual(num_updated, 0) + + ar1.refresh_from_db() + self.assertIsInstance(ar1.published, datetime) + + ar2.published = Now() + timedelta(days=2) + ar2.save() + ar2.refresh_from_db() + self.assertIsInstance(ar2.published, datetime) + + self.assertQuerysetEqual( + Article.objects.filter(published__lte=Now()), + ['How to Django'], + lambda a: a.title + ) + self.assertQuerysetEqual( + Article.objects.filter(published__gt=Now()), + ['How to Time Travel'], + lambda a: a.title + )