| | 17 | |
| | 18 | |
| | 19 | --- Edit: |
| | 20 | |
| | 21 | Commenting out that line that I am unhappy about will solve my `raw()` problems, but will cause problems elsewhere. My current desperate solution, which seems to solve my issues is to monkey patch the things I didn't want: |
| | 22 | |
| | 23 | 1. Don't disable the psycopg2 defaults |
| | 24 | 2. In the SQLCompiler, when doing conversions, if the conversion is for JSON, assume that psycopg2 has already handled it and skip it |
| | 25 | |
| | 26 | It is very hamfisted, but it works. Any pointers for more sensible solution would be much appreciated :) |
| | 27 | |
| | 28 | |
| | 29 | {{{ |
| | 30 | @async_unsafe |
| | 31 | def monkey_get_new_connection(self, conn_params): |
| | 32 | connection = Database.connect(**conn_params) |
| | 33 | |
| | 34 | # self.isolation_level must be set: |
| | 35 | # - after connecting to the database in order to obtain the database's |
| | 36 | # default when no value is explicitly specified in options. |
| | 37 | # - before calling _set_autocommit() because if autocommit is on, that |
| | 38 | # will set connection.isolation_level to ISOLATION_LEVEL_AUTOCOMMIT. |
| | 39 | options = self.settings_dict['OPTIONS'] |
| | 40 | try: |
| | 41 | self.isolation_level = options['isolation_level'] |
| | 42 | except KeyError: |
| | 43 | self.isolation_level = connection.isolation_level |
| | 44 | else: |
| | 45 | # Set the isolation level to the value from OPTIONS. |
| | 46 | if self.isolation_level != connection.isolation_level: |
| | 47 | connection.set_session(isolation_level=self.isolation_level) |
| | 48 | |
| | 49 | # --- Monkey: This line was introduces by Django team, which changes the |
| | 50 | # --- defaults of psycopg2. We need to not do that. |
| | 51 | # --- (https://code.djangoproject.com/ticket/31991) |
| | 52 | # Register dummy loads() to avoid a round trip from psycopg2's decode |
| | 53 | # to json.dumps() to json.loads(), when using a custom decoder in |
| | 54 | # JSONField. |
| | 55 | #psycopg2.extras.register_default_jsonb(conn_or_curs=connection, loads=lambda x: x) |
| | 56 | # --- |
| | 57 | return connection |
| | 58 | DatabaseWrapper.get_new_connection = monkey_get_new_connection |
| | 59 | |
| | 60 | |
| | 61 | def monkey_apply_converters(self, rows, converters): |
| | 62 | connection = self.connection |
| | 63 | converters = list(converters.items()) |
| | 64 | for row in map(list, rows): |
| | 65 | for pos, (convs, expression) in converters: |
| | 66 | value = row[pos] |
| | 67 | for converter in convs: |
| | 68 | # --- Monkey: `monkey_get_new_connection` now lets psycopg2 deal |
| | 69 | # --- with JSON conversion for us, so when we arrive at this point |
| | 70 | # --- it'll already be a dict. So if the converter is for JSON, |
| | 71 | # --- We can safely skip it |
| | 72 | module_name = str(inspect.getmodule(converter)) |
| | 73 | is_json = 'django/db/models/fields/json.py' in module_name |
| | 74 | is_array = 'django/contrib/postgres/fields/array.py' in module_name |
| | 75 | if is_json or is_array: |
| | 76 | continue |
| | 77 | # --- |
| | 78 | value = converter(value, expression, connection) |
| | 79 | row[pos] = value |
| | 80 | yield row |
| | 81 | SQLCompiler.apply_converters = monkey_apply_converters |
| | 82 | }}} |