1 | from django.db.models.sql.compiler import SQLInsertCompiler as BaseSQLInsertCompiler
|
---|
2 | from django.db.backends.postgresql.compiler import SQLInsertCompiler, InsertUnnest
|
---|
3 | def monkey_patch_assemble_as_sql(self, fields, value_rows):
|
---|
4 | # Specialize bulk-insertion of literal values through UNNEST to
|
---|
5 | # reduce the time spent planning the query.
|
---|
6 | fields_are_data = [_ for _ in fields if _.get_internal_type() != "ForeignKey"]
|
---|
7 | if (
|
---|
8 | # The optimization is not worth doing if there is a single
|
---|
9 | # row as it will result in the same number of placeholders.
|
---|
10 | len(value_rows) <= 1
|
---|
11 | # Lack of fields denote the usage of the DEFAULT keyword
|
---|
12 | # for the insertion of empty rows.
|
---|
13 | or any(field is None for field in fields)
|
---|
14 | # Fields that don't use standard internal types might not be
|
---|
15 | # unnest'able (e.g. array and geometry types are known to be
|
---|
16 | # problematic).
|
---|
17 | or any(
|
---|
18 | field.get_internal_type() not in self.connection.data_types
|
---|
19 | for field in fields_are_data
|
---|
20 | )
|
---|
21 | # Compilable cannot be combined in an array of literal values.
|
---|
22 | or any(any(hasattr(value, "as_sql") for value in row) for row in value_rows)
|
---|
23 | ):
|
---|
24 | return BaseSQLInsertCompiler.assemble_as_sql(self, fields, value_rows)
|
---|
25 | db_types = [field.db_type(self.connection) for field in fields]
|
---|
26 | return InsertUnnest(["(%%s)::%s[]" % db_type for db_type in db_types]), [
|
---|
27 | list(map(list, zip(*value_rows)))
|
---|
28 | ]
|
---|
29 | SQLInsertCompiler.assemble_as_sql = monkey_patch_assemble_as_sql
|
---|