Fixed #24894 -- Added contrib.postgres.functions.TransactionNow
This commit is contained in:
parent
3872a33132
commit
d34d39ade7
|
@ -0,0 +1,11 @@
|
||||||
|
from django.db.models import DateTimeField
|
||||||
|
from django.db.models.functions import Func
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionNow(Func):
|
||||||
|
template = 'CURRENT_TIMESTAMP'
|
||||||
|
|
||||||
|
def __init__(self, output_field=None, **extra):
|
||||||
|
if output_field is None:
|
||||||
|
output_field = DateTimeField()
|
||||||
|
super(TransactionNow, self).__init__(output_field=output_field, **extra)
|
|
@ -0,0 +1,31 @@
|
||||||
|
PostgreSQL specific database functions
|
||||||
|
======================================
|
||||||
|
|
||||||
|
All of these functions are available from the
|
||||||
|
``django.contrib.postgres.functions`` module.
|
||||||
|
|
||||||
|
.. currentmodule:: django.contrib.postgres.functions
|
||||||
|
|
||||||
|
TransactionNow
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. class:: TransactionNow()
|
||||||
|
|
||||||
|
.. versionadded:: 1.9
|
||||||
|
|
||||||
|
Returns the date and time on the database server that the current transaction
|
||||||
|
started. If you are not in a transaction it will return the date and time of
|
||||||
|
the current statement. This is a complement to
|
||||||
|
:class:`django.db.models.functions.Now`, which returns the date and time of the
|
||||||
|
current statement.
|
||||||
|
|
||||||
|
Note that only the outermost call to :func:`~django.db.transaction.atomic()`
|
||||||
|
sets up a transaction and thus sets the time that ``TransactionNow()`` will
|
||||||
|
return; nested calls create savepoints which do not affect the transaction
|
||||||
|
time.
|
||||||
|
|
||||||
|
Usage example::
|
||||||
|
|
||||||
|
>>> from django.contrib.postgres.functions import TransactionNow
|
||||||
|
>>> Article.objects.filter(published__lte=TransactionNow())
|
||||||
|
[<Article: How to Django>]
|
|
@ -34,6 +34,7 @@ Psycopg2 2.5 or higher is required.
|
||||||
aggregates
|
aggregates
|
||||||
fields
|
fields
|
||||||
forms
|
forms
|
||||||
|
functions
|
||||||
lookups
|
lookups
|
||||||
operations
|
operations
|
||||||
validators
|
validators
|
||||||
|
|
|
@ -203,7 +203,8 @@ Now
|
||||||
|
|
||||||
.. versionadded:: 1.9
|
.. versionadded:: 1.9
|
||||||
|
|
||||||
Returns the database server's current date and time when the query is executed.
|
Returns the database server's current date and time when the query is executed,
|
||||||
|
typically using the SQL ``CURRENT_TIMESTAMP``.
|
||||||
|
|
||||||
Usage example::
|
Usage example::
|
||||||
|
|
||||||
|
@ -211,6 +212,13 @@ Usage example::
|
||||||
>>> Article.objects.filter(published__lte=Now())
|
>>> Article.objects.filter(published__lte=Now())
|
||||||
[<Article: How to Django>]
|
[<Article: How to Django>]
|
||||||
|
|
||||||
|
.. admonition:: PostgreSQL considerations
|
||||||
|
|
||||||
|
On PostgreSQL, the SQL ``CURRENT_TIMESTAMP`` returns the time that the
|
||||||
|
current transaction started. Therefore for cross-database compatibility,
|
||||||
|
``Now()`` uses ``STATEMENT_TIMESTAMP`` instead. If you need the transaction
|
||||||
|
timestamp, use :class:`django.contrib.postgres.functions.TransactionNow`.
|
||||||
|
|
||||||
Substr
|
Substr
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -141,13 +141,18 @@ Minor features
|
||||||
|
|
||||||
* Added support for the :lookup:`rangefield.contained_by` lookup for some built
|
* Added support for the :lookup:`rangefield.contained_by` lookup for some built
|
||||||
in fields which correspond to the range fields.
|
in fields which correspond to the range fields.
|
||||||
|
|
||||||
* Added :class:`~django.contrib.postgres.fields.JSONField`.
|
* Added :class:`~django.contrib.postgres.fields.JSONField`.
|
||||||
|
|
||||||
* Added :doc:`/ref/contrib/postgres/aggregates`.
|
* Added :doc:`/ref/contrib/postgres/aggregates`.
|
||||||
|
|
||||||
* Fixed serialization of
|
* Fixed serialization of
|
||||||
:class:`~django.contrib.postgres.fields.DateRangeField` and
|
:class:`~django.contrib.postgres.fields.DateRangeField` and
|
||||||
:class:`~django.contrib.postgres.fields.DateTimeRangeField`.
|
:class:`~django.contrib.postgres.fields.DateTimeRangeField`.
|
||||||
|
|
||||||
|
* Added the :class:`~django.contrib.postgres.functions.TransactionNow` database
|
||||||
|
function.
|
||||||
|
|
||||||
:mod:`django.contrib.redirects`
|
:mod:`django.contrib.redirects`
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,13 @@ class Migration(migrations.Migration):
|
||||||
('related_field', models.ForeignKey('postgres_tests.AggregateTestModel', null=True)),
|
('related_field', models.ForeignKey('postgres_tests.AggregateTestModel', null=True)),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='NowTestModel',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('when', models.DateTimeField(null=True, default=None)),
|
||||||
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
pg_92_operations = [
|
pg_92_operations = [
|
||||||
|
|
|
@ -109,3 +109,7 @@ class StatTestModel(models.Model):
|
||||||
int1 = models.IntegerField()
|
int1 = models.IntegerField()
|
||||||
int2 = models.IntegerField()
|
int2 = models.IntegerField()
|
||||||
related_field = models.ForeignKey(AggregateTestModel, null=True)
|
related_field = models.ForeignKey(AggregateTestModel, null=True)
|
||||||
|
|
||||||
|
|
||||||
|
class NowTestModel(models.Model):
|
||||||
|
when = models.DateTimeField(null=True, default=None)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from django.contrib.postgres.functions import TransactionNow
|
||||||
|
|
||||||
|
from . import PostgreSQLTestCase
|
||||||
|
from .models import NowTestModel
|
||||||
|
|
||||||
|
|
||||||
|
class TestTransactionNow(PostgreSQLTestCase):
|
||||||
|
|
||||||
|
def test_transaction_now(self):
|
||||||
|
"""
|
||||||
|
The test case puts everything under a transaction, so two models
|
||||||
|
updated with a short gap should have the same time.
|
||||||
|
"""
|
||||||
|
m1 = NowTestModel.objects.create()
|
||||||
|
m2 = NowTestModel.objects.create()
|
||||||
|
|
||||||
|
NowTestModel.objects.filter(id=m1.id).update(when=TransactionNow())
|
||||||
|
sleep(0.1)
|
||||||
|
NowTestModel.objects.filter(id=m2.id).update(when=TransactionNow())
|
||||||
|
|
||||||
|
m1.refresh_from_db()
|
||||||
|
m2.refresh_from_db()
|
||||||
|
|
||||||
|
self.assertIsInstance(m1.when, datetime)
|
||||||
|
self.assertEqual(m1.when, m2.when)
|
Loading…
Reference in New Issue