Hello,
currently get_or_create(params) is implemented (imprecisely) this way:
try:
self.get(params)
except DoesNotExist:
self._create_object_from_params(params)
This creates concurrency problem, as the object might get created by
another thread, after get(params) threw an exception and before
_create_object_from_params has started.
Luckily Postgresql lets combine the above statements into a single
structured query. This should be a performance gain as for the DB is
faster to execute one than a two queries.
Consider this:
CREATE TABLE t (
id SERIAL PRIMARY KEY,
name VARCHAR(10) NOT NULL UNIQUE,
comment VARCHAR(10));
And here comes the magic:
WITH
to_be_inserted AS (SELECT 'nameD' as "name", 'comment13' as "comment"),
just_inserted AS (
INSERT INTO t (name, comment) SELECT * FROM to_be_inserted
WHERE NOT EXISTS(
SELECT * FROM t WHERE
t.name='nameD')
RETURNING *)
SELECT *, FALSE as "created" FROM t WHERE
t.name='nameD' UNION ALL
SELECT *, TRUE AS "created" FROM just_inserted;
where "to_be_inserted contains" the values for the new object ('default'
parameter of get_or_create) and 'nameB' is the criterion passed to get().
Regards
Дилян