| 1 | | Replying to [comment:9 Garvit Sharma]: |
| 2 | | > Still reproducible on main (08e4c0d8e7), though the failure is not where the original patch targets. |
| 3 | | > |
| 4 | | > Minimal reproduction: |
| 5 | | > |
| 6 | | > {{{#!python |
| 7 | | > class Thing(models.Model): |
| 8 | | > price = models.IntegerField(db_column="cost%") |
| 9 | | > }}} |
| 10 | | > |
| 11 | | > {{{#!python |
| 12 | | > |
| 13 | | > str(Thing.objects.filter(price=5).query) |
| 14 | | > ValueError: unsupported format character '"' (0x22) at index 55 |
| 15 | | > |
| 16 | | > str(Thing.objects.all().query) |
| 17 | | > TypeError: not enough arguments for format string |
| 18 | | > }}} |
| 19 | | > |
| 20 | | > Both come from Query.__str__ in django/db/models/sql/query.py: |
| 21 | | > |
| 22 | | > {{{#!python |
| 23 | | > def str(self): |
| 24 | | > sql, params = self.sql_with_params() |
| 25 | | > return sql % params |
| 26 | | > }}} |
| 27 | | > |
| 28 | | > The % in the column name is read as the start of a format specifier by the % operator. With params present it fails on the character following %; with no params it fails for lack of arguments. |
| 29 | | > |
| 30 | | > sql_with_params() is unaffected and returns the correct SQL and parameters: |
| 31 | | > |
| 32 | | > {{{#!python |
| 33 | | > |
| 34 | | > Thing.objects.filter(price=5).query.sql_with_params() |
| 35 | | > ('SELECT "check_app_thing"."id", "check_app_thing"."cost%" FROM "check_app_thing" WHERE "check_app_thing"."cost%" = %s', (5,)) |
| 36 | | > }}} |
| 37 | | > |
| 38 | | > Query execution also works on SQLite, where the driver uses qmark paramstyle. I have not tested execution on MySQL or PostgreSQL, where substitution happens inside the driver — that path may still fail as originally reported. |
| 39 | | > |
| 40 | | > Since Query.__str__ is in the generic SQL layer rather than a backend, this failure appears to be backend-independent, but I have only tested SQLite. |
| 41 | | > |
| 42 | | > I'd like to work on this. |
| 43 | | |