Skip to content

Commit 47db328

Browse files
committed
Documented all features
1 parent 4ec3e79 commit 47db328

File tree

3 files changed

+51
-86
lines changed

3 files changed

+51
-86
lines changed

README.rst

Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -68,81 +68,10 @@ Installation
6868
}
6969
}
7070
71-
Usage
72-
-----
73-
74-
* ``psqlextra.models.PostgresModel``
75-
Inheriting your models from this gives you access to the ``PostgresManager``, which exposes:
76-
77-
* ``upsert``:
78-
79-
* Native, single query, concurrency safe upsert:
80-
81-
.. code-block:: python
82-
83-
from psqlextra.models import PostgresModel
84-
85-
class MyModel(PostgresModel):
86-
title = models.CharField(unique=True)
87-
88-
pk1 = MyModel.objects.upsert(title='beer')
89-
pk2 = MyModel.objects.upsert(title='beer')
90-
91-
assert pk1 == pk2
92-
93-
* ``upsert_and_get``:
94-
95-
* Native, single query, concurrency safe upsert + select:
96-
97-
.. code-block:: python
98-
99-
from psqlextra.models import PostgresModel
100-
101-
class MyModel(PostgresModel):
102-
title = models.CharField(unique=True)
103-
104-
pk1 = MyModel.objects.upsert(title='beer')
105-
obj2 = MyModel.objects.upsert_and_get(title='beer')
106-
107-
assert pk1 == obj2.pk
108-
109-
Upserts use PostgreSQL's ``ON CONFLICT`` clause. This instruct PostgreSQL to overwrite
110-
an existing row when it encounters a conflict (duplicate key). This happens in a single
111-
query. PostgreSQL guarentees concurrency safety for ``ON CONFLICT``.
112-
113-
* ``psqlextra.fields.HStoreField``
114-
Inherits from Django's ``HStoreField`` but adds support for constraints:
115-
116-
* ``uniqueness``:
117-
118-
* Enforce uniqueness for one or more key:
119-
120-
.. code-block:: python
121-
122-
from psqlextra.fields import HStoreField
123-
124-
class MyModel(models.Model):
125-
title = HStoreField(uniqueness=['en', 'ro'])
126-
127-
* Enforce uniqueness for one ore more keys **together** (similar to Django's ``unique_together``):
128-
129-
.. code-block:: python
130-
131-
from psqlextra.fields import HStoreField
132-
133-
class MyModel(models.Model):
134-
title = HStoreField(uniqueness=[('en', 'ro')])
135-
136-
* ``required``:
137-
138-
* Require one or more keys to be set:
139-
140-
.. code-block:: python
141-
142-
from psqlextra.fields import HStoreField
71+
Documentation
72+
-------------
14373

144-
class MyModel(models.Model):
145-
title = HStoreField(required=['h1', 'h2'])
74+
Browse the documentation at: [http://django-postgres-extra.readthedocs.io/](http://django-postgres-extra.readthedocs.io/).
14675

14776

14877
FAQ - Frequently asked questions

docs/features.md

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
# Overview
2-
31
# HStoreField
42
`psqlextra.fields.HStoreField` is based on Django's [HStoreField](https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#hstorefield) and therefor supports everything Django does natively, plus more.
53

6-
## Constraints
7-
### uniqueness
4+
## uniqueness
85
The `uniqueness` constraint can be added on one or more `hstore` keys, similar to how a `UNIQUE` constraint can be added to a column. Setting this option causes unique indexes to be created on the specified keys.
96

107
You can specify a `list` of strings to specify the keys that must be marked as unique:
@@ -26,7 +23,7 @@ Uniqueness can also be enforced "together", similar to Django's [unique_together
2623

2724
In the example above, `key1` and `key2` must unique **together**, and `key3` must unique on its own. By default, none of the keys are marked as "unique".
2825

29-
### required
26+
## required
3027
The `required` option can be added to ensure that the specified `hstore` keys are set for every row. This is similar to a `NOT NULL` constraint on a column. You can specify a list of `hstore` keys that are required:
3128

3229
from psqlextra.fields import HStoreField
@@ -39,3 +36,41 @@ The `required` option can be added to ensure that the specified `hstore` keys ar
3936
MyModel.objects.create(myfield={'key2': 'value1'})
4037

4138
Both calls to `create` would fail in the example above since they do not provide a non-null value for `key1`. By default, none of the keys are required.
39+
40+
# Upsert
41+
An "upsert" is an operation where a piece of data is inserted/created if it doesn't exist yet and updated (overwritten) when it already exists. Django has long provided this functionality through [`update_or_create`](https://docs.djangoproject.com/en/1.10/ref/models/querysets/#update-or-create). It does this by first checking whether the record exists and creating it not.
42+
43+
The major problem with this approach is possibility of race conditions. In between the `SELECT` and `INSERT`, another process could perform the `INSERT`. The last `INSERT` would most likely fail because it would be duplicating a `UNIQUE` constaint.
44+
45+
In order to combat this, PostgreSQL added native upserts. Also known as [`ON CONFLICT DO ...`](https://www.postgresql.org/docs/9.5/static/sql-insert.html#SQL-ON-CONFLICT). This allows a user to specify what to do when a conflict occurs.
46+
47+
48+
## upsert
49+
The `upsert` method attempts to insert a row with the specified data or updates (and overwrites) the duplicate row, and then returns the primary key of the row that was created/updated:
50+
51+
from django.db import models
52+
from psqlextra.models import PostgresModel
53+
54+
class MyModel(PostgresModel):
55+
myfield = models.CharField(max_length=255, unique=True)
56+
57+
id1 = MyModel.objects.upsert(myfield='beer')
58+
id2 = MyModel.objects.upsert(myfield='beer')
59+
60+
assert id1 == id2
61+
62+
Note that a single call to `upsert` results in a single `INSERT INTO` statement. It is therefor much faster and much safer than anything Django currently has to offer.
63+
64+
## upsert_and_get
65+
`upsert_and_get` does the same thing as `upsert`, but returns a model instance rather than the primary key of the row that was created/updated. This also happens in a single query using `RETURNING` clause on the `INSERT INTO` statement:
66+
67+
from django.db import models
68+
from psqlextra.models import PostgresModel
69+
70+
class MyModel(PostgresModel):
71+
myfield = models.CharField(max_length=255, unique=True)
72+
73+
obj1 = MyModel.objects.upsert_and_get(myfield='beer')
74+
obj2 = MyModel.objects.upsert_and_get(myfield='beer')
75+
76+
assert obj1.id == obj2.id

docs/index.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ django-postgres-extra aims to make all of PostgreSQL's awesome features availabl
55
With seamless we mean that any features we add will work truly seamlessly. You should not have to manually modify your migrations to work with fields and objects provided by this package.
66

77
## PostgreSQL features
8-
We are currently aiming on having the following features available:
8+
Explore the [Features](/features/) page for detailed instructions and information on how to use all features.
99

10-
* [hstore](https://www.postgresql.org/docs/9.1/static/hstore.html)
11-
* UNIQUE constaints
12-
* NOT-NULL constaints
10+
* [hstore](/features/#hstorefield)
11+
* [`uniqueness`](/features/#uniqueness)
12+
* [`required`](/features/#required)
1313

14-
* [ltree](https://www.postgresql.org/docs/9.1/static/ltree.html)
15-
16-
* [native upsert](https://www.postgresql.org/docs/9.5/static/sql-insert.html#SQL-ON-CONFLICT)
14+
* [upsert](/features/#upsert)
15+
* [`upsert`](http://localhost:8000/features/#upsert_1)
16+
* [`upsert_and_get`](http://localhost:8000/features/#upsert_and_get)
1717

1818
## Installation
1919

@@ -44,5 +44,6 @@ In order to use this package, your project must be using:
4444

4545
* Python 3.5, or newer
4646
* PostgreSQL 9.6 or newer
47+
* Django 1.10 or newer
4748

4849
Python 3.5 is required because type hints are used. A feature only available in Python 3.5 and newer. PostgreSQL 9.6 is required to take advantage of the latest features such as `ltree`.

0 commit comments

Comments
 (0)