diff --git a/.travis.yml b/.travis.yml
index d86443f..810ab65 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,77 +5,81 @@ cache: pip
services:
- postgresql
addons:
- postgresql: "11"
+ postgresql: "12"
apt:
packages:
- postgresql-10
- postgresql-client-10
- postgresql-11
- postgresql-client-11
- - systemd-sysv
-
+ - postgresql-12
+ - postgresql-client-12
python:
- 2.7
- - 3.4
- 3.5
- 3.6
- 3.7
+ - 3.8
env:
- - DJANGO=1.7 PG=9.3
- DJANGO=1.7 PG=9.4
- DJANGO=1.7 PG=9.5
- DJANGO=1.7 PG=9.6
- DJANGO=1.7 PG=10
- DJANGO=1.7 PG=11
- - DJANGO=1.8 PG=9.3
+ - DJANGO=1.7 PG=12
- DJANGO=1.8 PG=9.4
- DJANGO=1.8 PG=9.5
- DJANGO=1.8 PG=9.6
- DJANGO=1.8 PG=10
- DJANGO=1.8 PG=11
- - DJANGO=1.9 PG=9.3
+ - DJANGO=1.8 PG=12
- DJANGO=1.9 PG=9.4
- DJANGO=1.9 PG=9.5
- DJANGO=1.9 PG=9.6
- DJANGO=1.9 PG=10
- DJANGO=1.9 PG=11
- - DJANGO=1.10 PG=9.3
+ - DJANGO=1.9 PG=12
- DJANGO=1.10 PG=9.4
- DJANGO=1.10 PG=9.5
- DJANGO=1.10 PG=9.6
- DJANGO=1.10 PG=10
- DJANGO=1.10 PG=11
- - DJANGO=1.11 PG=9.3
+ - DJANGO=1.10 PG=12
- DJANGO=1.11 PG=9.4
- DJANGO=1.11 PG=9.5
- DJANGO=1.11 PG=9.6
- DJANGO=1.11 PG=10
- DJANGO=1.11 PG=11
- - DJANGO=2.0 PG=9.3
+ - DJANGO=1.11 PG=12
- DJANGO=2.0 PG=9.4
- DJANGO=2.0 PG=9.5
- DJANGO=2.0 PG=9.6
- DJANGO=2.0 PG=10
- DJANGO=2.0 PG=11
- - DJANGO=2.1 PG=9.3
+ - DJANGO=2.0 PG=12
- DJANGO=2.1 PG=9.4
- DJANGO=2.1 PG=9.5
- DJANGO=2.1 PG=9.6
- DJANGO=2.1 PG=10
- DJANGO=2.1 PG=11
- - DJANGO=2.2 PG=9.3
+ - DJANGO=2.1 PG=12
- DJANGO=2.2 PG=9.4
- DJANGO=2.2 PG=9.5
- DJANGO=2.2 PG=9.6
- DJANGO=2.2 PG=10
- DJANGO=2.2 PG=11
+ - DJANGO=2.2 PG=12
+ - DJANGO=3.0 PG=9.4
+ - DJANGO=3.0 PG=9.5
+ - DJANGO=3.0 PG=9.6
+ - DJANGO=3.0 PG=10
+ - DJANGO=3.0 PG=11
+ - DJANGO=3.0 PG=12
matrix:
exclude:
# Django 2.0+ doesn't support python 2.7
- - python: 2.7
- env: DJANGO=2.0 PG=9.3
- python: 2.7
env: DJANGO=2.0 PG=9.4
- python: 2.7
@@ -87,7 +91,7 @@ matrix:
- python: 2.7
env: DJANGO=2.0 PG=11
- python: 2.7
- env: DJANGO=2.1 PG=9.3
+ env: DJANGO=2.0 PG=12
- python: 2.7
env: DJANGO=2.1 PG=9.4
- python: 2.7
@@ -99,7 +103,7 @@ matrix:
- python: 2.7
env: DJANGO=2.1 PG=11
- python: 2.7
- env: DJANGO=2.2 PG=9.3
+ env: DJANGO=2.1 PG=12
- python: 2.7
env: DJANGO=2.2 PG=9.4
- python: 2.7
@@ -110,36 +114,44 @@ matrix:
env: DJANGO=2.2 PG=10
- python: 2.7
env: DJANGO=2.2 PG=11
+ - python: 2.7
+ env: DJANGO=2.2 PG=12
+ - python: 2.7
+ env: DJANGO=3.0 PG=9.4
+ - python: 2.7
+ env: DJANGO=3.0 PG=9.5
+ - python: 2.7
+ env: DJANGO=3.0 PG=9.6
+ - python: 2.7
+ env: DJANGO=3.0 PG=10
+ - python: 2.7
+ env: DJANGO=3.0 PG=11
+ - python: 2.7
+ env: DJANGO=3.0 PG=12
- # Django 2.1+ doesn't support python 3.4
- - python: 3.4
- env: DJANGO=2.1 PG=9.3
- - python: 3.4
- env: DJANGO=2.1 PG=9.4
- - python: 3.4
- env: DJANGO=2.1 PG=9.5
- - python: 3.4
- env: DJANGO=2.1 PG=9.6
- - python: 3.4
- env: DJANGO=2.1 PG=10
- - python: 3.4
- env: DJANGO=2.1 PG=11
- - python: 3.4
- env: DJANGO=2.2 PG=9.3
- - python: 3.4
- env: DJANGO=2.2 PG=9.4
- - python: 3.4
- env: DJANGO=2.2 PG=9.5
- - python: 3.4
- env: DJANGO=2.2 PG=9.6
- - python: 3.4
- env: DJANGO=2.2 PG=10
- - python: 3.4
- env: DJANGO=2.2 PG=11
+ # Django 3.0+ doesn't support python 3.5
+ - python: 3.5
+ env: DJANGO=3.0 PG=9.4
+ - python: 3.5
+ env: DJANGO=3.0 PG=9.5
+ - python: 3.5
+ env: DJANGO=3.0 PG=9.6
+ - python: 3.5
+ env: DJANGO=3.0 PG=10
+ - python: 3.5
+ env: DJANGO=3.0 PG=11
+ - python: 3.5
+ env: DJANGO=3.0 PG=12
+
+ # Django 3.0+ doesn't support Postgresql 9.4
+ - python: 3.6
+ env: DJANGO=3.0 PG=9.4
+ - python: 3.7
+ env: DJANGO=3.0 PG=9.4
+ - python: 3.8
+ env: DJANGO=3.0 PG=9.4
# Django 1.7 doesn't support python 3.5+
- - python: 3.5
- env: DJANGO=1.7 PG=9.3
- python: 3.5
env: DJANGO=1.7 PG=9.4
- python: 3.5
@@ -150,8 +162,8 @@ matrix:
env: DJANGO=1.7 PG=10
- python: 3.5
env: DJANGO=1.7 PG=11
- - python: 3.6
- env: DJANGO=1.7 PG=9.3
+ - python: 3.5
+ env: DJANGO=1.7 PG=12
- python: 3.6
env: DJANGO=1.7 PG=9.4
- python: 3.6
@@ -162,8 +174,8 @@ matrix:
env: DJANGO=1.7 PG=10
- python: 3.6
env: DJANGO=1.7 PG=11
- - python: 3.7
- env: DJANGO=1.7 PG=9.3
+ - python: 3.6
+ env: DJANGO=1.7 PG=12
- python: 3.7
env: DJANGO=1.7 PG=9.4
- python: 3.7
@@ -174,11 +186,23 @@ matrix:
env: DJANGO=1.7 PG=10
- python: 3.7
env: DJANGO=1.7 PG=11
+ - python: 3.7
+ env: DJANGO=1.7 PG=12
+ - python: 3.8
+ env: DJANGO=1.7 PG=9.4
+ - python: 3.8
+ env: DJANGO=1.7 PG=9.5
+ - python: 3.8
+ env: DJANGO=1.7 PG=9.6
+ - python: 3.8
+ env: DJANGO=1.7 PG=10
+ - python: 3.8
+ env: DJANGO=1.7 PG=11
+ - python: 3.8
+ env: DJANGO=1.7 PG=12
- # python 3.6 has deprecated issue with django before 1.11
+ # python 3.6+ has deprecated issue with django before 1.11
# https://stackoverflow.com/questions/41343263/provide-classcell-example-for-python-3-6-metaclass\
- - python: 3.6
- env: DJANGO=1.8 PG=9.3
- python: 3.6
env: DJANGO=1.8 PG=9.4
- python: 3.6
@@ -189,8 +213,8 @@ matrix:
env: DJANGO=1.8 PG=10
- python: 3.6
env: DJANGO=1.8 PG=11
- - python: 3.7
- env: DJANGO=1.8 PG=9.3
+ - python: 3.6
+ env: DJANGO=1.8 PG=12
- python: 3.7
env: DJANGO=1.8 PG=9.4
- python: 3.7
@@ -201,8 +225,20 @@ matrix:
env: DJANGO=1.8 PG=10
- python: 3.7
env: DJANGO=1.8 PG=11
- - python: 3.6
- env: DJANGO=1.9 PG=9.3
+ - python: 3.7
+ env: DJANGO=1.8 PG=12
+ - python: 3.8
+ env: DJANGO=1.8 PG=9.4
+ - python: 3.8
+ env: DJANGO=1.8 PG=9.5
+ - python: 3.8
+ env: DJANGO=1.8 PG=9.6
+ - python: 3.8
+ env: DJANGO=1.8 PG=10
+ - python: 3.8
+ env: DJANGO=1.8 PG=11
+ - python: 3.8
+ env: DJANGO=1.8 PG=12
- python: 3.6
env: DJANGO=1.9 PG=9.4
- python: 3.6
@@ -212,9 +248,7 @@ matrix:
- python: 3.6
env: DJANGO=1.9 PG=10
- python: 3.6
- env: DJANGO=1.9 PG=11
- - python: 3.7
- env: DJANGO=1.9 PG=9.3
+ env: DJANGO=1.9 PG=12
- python: 3.7
env: DJANGO=1.9 PG=9.4
- python: 3.7
@@ -225,8 +259,20 @@ matrix:
env: DJANGO=1.9 PG=10
- python: 3.7
env: DJANGO=1.9 PG=11
- - python: 3.6
- env: DJANGO=1.10 PG=9.3
+ - python: 3.7
+ env: DJANGO=1.9 PG=12
+ - python: 3.8
+ env: DJANGO=1.9 PG=9.4
+ - python: 3.8
+ env: DJANGO=1.9 PG=9.5
+ - python: 3.8
+ env: DJANGO=1.9 PG=9.6
+ - python: 3.8
+ env: DJANGO=1.9 PG=10
+ - python: 3.8
+ env: DJANGO=1.9 PG=11
+ - python: 3.8
+ env: DJANGO=1.9 PG=12
- python: 3.6
env: DJANGO=1.10 PG=9.4
- python: 3.6
@@ -237,8 +283,8 @@ matrix:
env: DJANGO=1.10 PG=10
- python: 3.6
env: DJANGO=1.10 PG=11
- - python: 3.7
- env: DJANGO=1.10 PG=9.3
+ - python: 3.6
+ env: DJANGO=1.10 PG=12
- python: 3.7
env: DJANGO=1.10 PG=9.4
- python: 3.7
@@ -249,13 +295,29 @@ matrix:
env: DJANGO=1.10 PG=10
- python: 3.7
env: DJANGO=1.10 PG=11
-
+ - python: 3.7
+ env: DJANGO=1.10 PG=12
+ - python: 3.8
+ env: DJANGO=1.10 PG=9.4
+ - python: 3.8
+ env: DJANGO=1.10 PG=9.5
+ - python: 3.8
+ env: DJANGO=1.10 PG=9.6
+ - python: 3.8
+ env: DJANGO=1.10 PG=10
+ - python: 3.8
+ env: DJANGO=1.10 PG=11
+ - python: 3.8
+ env: DJANGO=1.10 PG=12
before_install:
- # Use default PostgreSQL 11 port
+ # Set up PostgreSQL 11 and 12
- sudo sed -i 's/port = 5433/port = 5432/' /etc/postgresql/11/main/postgresql.conf
- sudo cp /etc/postgresql/{10,11}/main/pg_hba.conf
+ - sudo sed -i 's/port = 5434/port = 5432/' /etc/postgresql/12/main/postgresql.conf
+ - sudo cp /etc/postgresql/{10,12}/main/pg_hba.conf
+
# Start PostgreSQL version we need
- sudo systemctl stop postgresql
- sudo systemctl start postgresql@$PG-main
diff --git a/README.md b/README.md
index 88ccdf3..849859f 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ A small library implementing PostgreSQL ability to return rows in DML statements
[Link to PostgreSQL docs](https://www.postgresql.org/docs/10/static/sql-update.html)
## Requirements
-* Python 2.7 or Python 3.4+
+* Python 2.7 or Python 3.5+
* django >= 1.7
Previous versions may also work, but haven't been tested.
bulk_create_returning method doesn't support .only() and .defer() filters for django before 1.10.
@@ -11,7 +11,7 @@ A small library implementing PostgreSQL ability to return rows in DML statements
* six
* typing
* psycopg2
-* PostgreSQL 9.3+
+* PostgreSQL 9.4+
Previous versions may also work, but haven't been tested.
## Installation
diff --git a/src/django_pg_returning/manager.py b/src/django_pg_returning/manager.py
index 7060966..84f833d 100644
--- a/src/django_pg_returning/manager.py
+++ b/src/django_pg_returning/manager.py
@@ -1,8 +1,8 @@
+from typing import Dict, Any, List, Type, Optional, Tuple
+
import django
from django.db import transaction, models
from django.db.models import sql, Field, QuerySet
-from typing import Dict, Any, List, Type, Optional, Tuple
-
from django.db.models.query import EmptyResultSet
from .compatibility import chain_query, get_model_fields
@@ -17,12 +17,12 @@ def _get_loaded_field_cb(target, model, fields):
"""
target[model] = fields
- def _insert(self, objs, fields, return_id=False, raw=False, using=None, ignore_conflicts=False):
+ def _insert(self, objs, fields, **kwargs):
"""
Replaces standard insert procedure for bulk_create_returning
"""
if not getattr(self.model, '_insert_returning', False):
- return QuerySet._insert(self, objs, fields, return_id=return_id, raw=raw, using=using)
+ return QuerySet._insert(self, objs, fields, **kwargs)
# Returns attname, not column.
# Before django 1.10 pk fields hasn't been returned from postgres.
@@ -33,13 +33,20 @@ def _insert(self, objs, fields, return_id=False, raw=False, using=None, ignore_c
"You can't fetch relative model fields with returning operation"
self._for_write = True
+ using = kwargs.get('using', None) or self.db
- kwargs = {} if django.VERSION < (2, 2) else {'ignore_conflicts': ignore_conflicts}
- query = sql.InsertQuery(self.model, **kwargs)
- query.insert_values(fields, objs, raw=raw)
+ query_kwargs = {} if django.VERSION < (2, 2) else {'ignore_conflicts': kwargs.get('ignore_conflicts')}
+ query = sql.InsertQuery(self.model, **query_kwargs)
+ query.insert_values(fields, objs, raw=kwargs.get('raw'))
self.model._insert_returning_cache = self._execute_sql(query, return_fields, using=using)
- return self.model._insert_returning_cache.values_list(self.model._meta.pk.column, flat=True) if return_id else None
+ if django.VERSION < (3,):
+ return self.model._insert_returning_cache.values_list(self.model._meta.pk.column, flat=True) \
+ if kwargs.get('return_id', False) else None
+ else:
+ returning_fields = kwargs.get('returning_fields', None)
+ return self.model._insert_returning_cache.values_list(*(f.column for f in returning_fields)) \
+ if returning_fields is not None else None
_insert.alters_data = True
_insert.queryset_only = False
@@ -92,7 +99,7 @@ def _get_returning_qs(self, query_type, values=None, **updates):
:raises AssertionError: If input data is invalid
"""
assert self.query.can_filter(), "Can not update or delete once a slice has been taken."
- assert getattr(self, '_fields', None) is None,\
+ assert getattr(self, '_fields', None) is None, \
"Can not call delete() or update() after .values() or .values_list()"
# Returns attname, not column.
@@ -169,7 +176,8 @@ def bulk_create_returning(self, objs, batch_size=None):
# Replace values fetched from returned data
if result and result[0].pk:
# For django 1.10+ where objects can be matched
- values_dict = {item[self.model._meta.pk.column]: item for item in self.model._insert_returning_cache.values()}
+ values_dict = {item[self.model._meta.pk.column]: item for item in
+ self.model._insert_returning_cache.values()}
for item in result:
for k, v in values_dict[item.pk].items():
setattr(item, k, v)