I’m trying to use bulk_create(..., ignore_conflicts=True) to insert records into a table. The ideal behavior for me would be to either:
Only return instances that were actually inserted
Or, just the number of instances actually inserted
The default behavior, at least in Postgres, is to return the count of records actually inserted. If there is a conflict, Postgres will not count that toward the count. Similarly, if using RETURNING "id" or similar, only the ids of records actually inserted will be returned.
Instead in Django, ALL objects are returned in a list, whether they were inserted or not.
Is there a way to mimic the Postgres behavior using the ORM?
FWIW this is the somewhat hacky but direct alternative using raw SQL I’ve come up with:
from django.utils import timezone
from django.db import connection
from psycopg2.extras import execute_values
# Other imports missing
now = timezone.now()
values = [(request.user.id, i.id, list_type, now, now) for i in ingredients]
query = """
INSERT INTO core_useringredient (user_id, ingredient_id, list_type, added, modified)
VALUES %s
ON CONFLICT DO NOTHING
RETURNING id
"""
with connection.cursor() as cursor:
execute_values(cursor, query, values)
inserted_ids = [row[0] for row in cursor.fetchall()]
So if we send in values to insert, but all conflict, inserted_ids is just an empty list.