Upon investigation, it seems that `AutoField.cast_db_type` uses the
inherited definition from `Field` and returns `AutoField.db_type`.
However `AutoField.db_type` returns 'serial', which is a "syntactical
sugar" (not a true type) in Postgresql and only valid for creation.
The issue arises when `AutoField.cast_db_type` also returns 'serial',
which is invalid.
More confusingly `AutoField.rel_db_type` has already been overridden and
correctly returns 'integer'.
I believe fixing this is as easy as copying the override of
`AutoField.rel_db_type` to `AutoField.cast_db_type`.
I'll try to at least get this implemented as a test on my fork, so that it
is easy to confirm, but in the mean time the models to reproduce are:
{{{
class Item(models.Model):
label = models.CharField(max_length=100)
cost = models.IntegerField()
class Activity(models.Model):
content_type = models.ForeignKey(ContentType,
on_delete=models.CASCADE)
object_pk = models.CharField(max_length=100)
generic_object = GenericForeignKey(fk_field='object_pk')
}}}
Reference:
PostgreSQL docs on 'serial' type
(https://www.postgresql.org/docs/10/static/datatype-numeric.html#DATATYPE-
SERIAL)
--
Ticket URL: <https://code.djangoproject.com/ticket/29569>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* cc: felixxm (added)
* version: 2.0 => master
* easy: 0 => 1
Comment:
Thanks for the report. It doesn't sound natural to me to cast to
`AutoField`, because if you want to get an `integer` / `bigint`, why not
use it directly? Nevertheless you can use
`DatabaseOperations.cast_data_types` to fix this easily. This issue
probably appears on other back-ends.
--
Ticket URL: <https://code.djangoproject.com/ticket/29569#comment:1>
* stage: Unreviewed => Accepted
--
Ticket URL: <https://code.djangoproject.com/ticket/29569#comment:2>
Comment (by Andrew Standley):
I'm using `Cast` on generic foreign keys to handle the type coercion in
the database, so I'm not coding around a 'known' field-type. I would
indeed just use an `IntegerField`, 'integer' type directly otherwise, and
as a temporary solution I'm doing just that for the edge case of
`AutoField`.
Can you elaborate on how I would use `DatabaseOperations.cast_data_types`
to fix this? I'm afraid I'm not familiar with that whole side of things.
It (perhaps naively) seems to me that `DatabaseOperations` is going to
have no effect on the `Cast` operation compilation as `Cast` selects the
`db_type` through a different route than the one that
`DatabaseOperations.cast_data_type` is used in.
Replying to [comment:1 felixxm]:
> Thanks for the report. It doesn't sound natural to me to cast to
`AutoField`, because if you want to get an `integer` / `bigint`, why not
use it directly? Nevertheless you can use
`DatabaseOperations.cast_data_types` to fix this easily. This issue
probably appears on other back-ends.
--
Ticket URL: <https://code.djangoproject.com/ticket/29569#comment:3>
Comment (by felixxm):
In Django we defined `DatabaseOperations` for each back-end.
`cast_db_type()` uses back-end specific dictionary
`connection.ops.cast_data_types` to find data type to use in the `Cast()`
(see
[https://github.com/django/django/blob/master/django/db/models/fields/__init__.py#L684-L689
django/db/models/fields/__init__.py]).
--
Ticket URL: <https://code.djangoproject.com/ticket/29569#comment:4>
* status: new => assigned
* owner: nobody => felixxm
* has_patch: 0 => 1
Comment:
[https://github.com/django/django/pull/10210 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/29569#comment:5>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/29569#comment:6>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"ac25dd1f8d48accc765c05aebb47c427e51f3255" ac25dd1f]:
{{{
#!CommitTicketReference repository=""
revision="ac25dd1f8d48accc765c05aebb47c427e51f3255"
Fixed #29569 -- Fixed Cast() with AutoField and BigAutoField.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/29569#comment:7>