summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Melchiorre <paolo@melchiorre.org>2017-03-29 23:52:42 +0200
committerTim Graham <timograham@gmail.com>2017-04-25 20:21:36 -0400
commitfcb5dbfec0542faaa1b0adad754a1caf1bcd65e2 (patch)
treea81d7f63382578206e943e539165fecf43c00e64
parent98ee57e343206ef553de78b22be5e9a6dacb5060 (diff)
Fixed #27996 -- Added RandomUUID function and CryptoExtension to contrib.postgres.
-rw-r--r--django/contrib/postgres/functions.py11
-rw-r--r--django/contrib/postgres/operations.py6
-rw-r--r--docs/ref/contrib/postgres/functions.txt20
-rw-r--r--docs/ref/contrib/postgres/operations.txt9
-rw-r--r--docs/releases/2.0.txt6
-rw-r--r--tests/postgres_tests/migrations/0001_setup_extensions.py6
-rw-r--r--tests/postgres_tests/migrations/0002_create_test_models.py7
-rw-r--r--tests/postgres_tests/models.py4
-rw-r--r--tests/postgres_tests/test_functions.py17
9 files changed, 81 insertions, 5 deletions
diff --git a/django/contrib/postgres/functions.py b/django/contrib/postgres/functions.py
index d17f9cb37d..36b32e0751 100644
--- a/django/contrib/postgres/functions.py
+++ b/django/contrib/postgres/functions.py
@@ -1,4 +1,13 @@
-from django.db.models import DateTimeField, Func
+from django.db.models import DateTimeField, Func, UUIDField
+
+
+class RandomUUID(Func):
+ template = 'GEN_RANDOM_UUID()'
+
+ def __init__(self, output_field=None, **extra):
+ if output_field is None:
+ output_field = UUIDField()
+ super().__init__(output_field=output_field, **extra)
class TransactionNow(Func):
diff --git a/django/contrib/postgres/operations.py b/django/contrib/postgres/operations.py
index 7544e38613..8ff043b5a9 100644
--- a/django/contrib/postgres/operations.py
+++ b/django/contrib/postgres/operations.py
@@ -35,6 +35,12 @@ class CITextExtension(CreateExtension):
self.name = 'citext'
+class CryptoExtension(CreateExtension):
+
+ def __init__(self):
+ self.name = 'pgcrypto'
+
+
class HStoreExtension(CreateExtension):
def __init__(self):
diff --git a/docs/ref/contrib/postgres/functions.txt b/docs/ref/contrib/postgres/functions.txt
index 465d423f6d..8d3df51864 100644
--- a/docs/ref/contrib/postgres/functions.txt
+++ b/docs/ref/contrib/postgres/functions.txt
@@ -7,6 +7,26 @@ All of these functions are available from the
.. currentmodule:: django.contrib.postgres.functions
+``RandomUUID``
+==============
+
+.. class:: RandomUUID()
+
+.. versionadded:: 2.0
+
+Returns a version 4 UUID.
+
+The `pgcrypto extension`_ must be installed. You can use the
+:class:`~django.contrib.postgres.operations.CryptoExtension` migration
+operation to install it.
+
+.. _pgcrypto extension: https://www.postgresql.org/docs/current/static/pgcrypto.html
+
+Usage example::
+
+ >>> from django.contrib.postgres.functions import RandomUUID
+ >>> Article.objects.update(uuid=RandomUUID())
+
``TransactionNow``
==================
diff --git a/docs/ref/contrib/postgres/operations.txt b/docs/ref/contrib/postgres/operations.txt
index 90cd007121..d984d9a3f7 100644
--- a/docs/ref/contrib/postgres/operations.txt
+++ b/docs/ref/contrib/postgres/operations.txt
@@ -67,6 +67,15 @@ run the query ``CREATE EXTENSION IF NOT EXISTS hstore;``.
Installs the ``citext`` extension.
+``CryptoExtension``
+===================
+
+.. class:: CryptoExtension()
+
+ .. versionadded:: 2.0
+
+ Installs the ``pgcrypto`` extension.
+
``HStoreExtension``
===================
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index 4babd84773..cc1248a9b0 100644
--- a/docs/releases/2.0.txt
+++ b/docs/releases/2.0.txt
@@ -87,6 +87,12 @@ Minor features
:class:`~django.contrib.postgres.aggregates.ArrayAgg` determines if
concatenated values will be distinct.
+* The new :class:`~django.contrib.postgres.functions.RandomUUID` database
+ function returns a version 4 UUID. It requires use of PostgreSQL's
+ ``pgcrypto`` extension which can be activated using the new
+ :class:`~django.contrib.postgres.operations.CryptoExtension` migration
+ operation.
+
:mod:`django.contrib.redirects`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/postgres_tests/migrations/0001_setup_extensions.py b/tests/postgres_tests/migrations/0001_setup_extensions.py
index d090ff7fd6..b00c6c0838 100644
--- a/tests/postgres_tests/migrations/0001_setup_extensions.py
+++ b/tests/postgres_tests/migrations/0001_setup_extensions.py
@@ -4,13 +4,14 @@ from django.db import migrations
try:
from django.contrib.postgres.operations import (
- BtreeGinExtension, CITextExtension, CreateExtension, HStoreExtension,
- TrigramExtension, UnaccentExtension,
+ BtreeGinExtension, CITextExtension, CreateExtension, CryptoExtension,
+ HStoreExtension, TrigramExtension, UnaccentExtension,
)
except ImportError:
BtreeGinExtension = mock.Mock()
CITextExtension = mock.Mock()
CreateExtension = mock.Mock()
+ CryptoExtension = mock.Mock()
HStoreExtension = mock.Mock()
TrigramExtension = mock.Mock()
UnaccentExtension = mock.Mock()
@@ -24,6 +25,7 @@ class Migration(migrations.Migration):
# Ensure CreateExtension quotes extension names by creating one with a
# dash in its name.
CreateExtension('uuid-ossp'),
+ CryptoExtension(),
HStoreExtension(),
TrigramExtension(),
UnaccentExtension(),
diff --git a/tests/postgres_tests/migrations/0002_create_test_models.py b/tests/postgres_tests/migrations/0002_create_test_models.py
index 842848dd47..4cd37e5e43 100644
--- a/tests/postgres_tests/migrations/0002_create_test_models.py
+++ b/tests/postgres_tests/migrations/0002_create_test_models.py
@@ -192,6 +192,13 @@ class Migration(migrations.Migration):
]
),
migrations.CreateModel(
+ name='UUIDTestModel',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('uuid', models.UUIDField(default=None, null=True)),
+ ]
+ ),
+ migrations.CreateModel(
name='RangesModel',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
diff --git a/tests/postgres_tests/models.py b/tests/postgres_tests/models.py
index 15fb5ab4ee..001ed00d0c 100644
--- a/tests/postgres_tests/models.py
+++ b/tests/postgres_tests/models.py
@@ -171,3 +171,7 @@ class StatTestModel(models.Model):
class NowTestModel(models.Model):
when = models.DateTimeField(null=True, default=None)
+
+
+class UUIDTestModel(models.Model):
+ uuid = models.UUIDField(default=None, null=True)
diff --git a/tests/postgres_tests/test_functions.py b/tests/postgres_tests/test_functions.py
index 620b561325..875a4b9520 100644
--- a/tests/postgres_tests/test_functions.py
+++ b/tests/postgres_tests/test_functions.py
@@ -1,10 +1,11 @@
+import uuid
from datetime import datetime
from time import sleep
-from django.contrib.postgres.functions import TransactionNow
+from django.contrib.postgres.functions import RandomUUID, TransactionNow
from . import PostgreSQLTestCase
-from .models import NowTestModel
+from .models import NowTestModel, UUIDTestModel
class TestTransactionNow(PostgreSQLTestCase):
@@ -26,3 +27,15 @@ class TestTransactionNow(PostgreSQLTestCase):
self.assertIsInstance(m1.when, datetime)
self.assertEqual(m1.when, m2.when)
+
+
+class TestRandomUUID(PostgreSQLTestCase):
+
+ def test_random_uuid(self):
+ m1 = UUIDTestModel.objects.create()
+ m2 = UUIDTestModel.objects.create()
+ UUIDTestModel.objects.update(uuid=RandomUUID())
+ m1.refresh_from_db()
+ m2.refresh_from_db()
+ self.assertIsInstance(m1.uuid, uuid.UUID)
+ self.assertNotEqual(m1.uuid, m2.uuid)