we use UUIDField for all primary keys on our models
we have a requirement to have an autoincrementing field as well
One cannot simply add an AutoField to the model, as it is required to be primary key, and we already have a primary key.
Have added a PositiveBigIntegerField for this purpose, and added a manual migration step to add a sequence/identity and apply it to the field. However, when an instance of the model is saved, it complains about a NULL value.
Assuming this is the correct approach, what is actually needed is for the compiled INSERT statement to either
not include the sequenced column in the insert (but still return the generated value via RETURNING) or
leverage the SQL DEFAULT keyword.
The latter feels like the correct approach, but I’m at a loss for how to achieve this. The objective is to transparently create a database-saved instance of this model with the ORM python instance of it containing the generated value (like you would see with an AutoField as PK).
With the recent extended support for db_returning, generated, and db_default in main I suspect this one might be easier to implement now if you want to have a shot at it. Happy to support you through code reviews.
@charettes thank you - that was the breadcrumb I needed. The following rough implementation works:
class Default(Expression):
def as_sql(self, compiler, connection):
return "DEFAULT", []
class AutoPositiveBigIntegerField(models.PositiveBigIntegerField):
@property
def db_returning(self):
return True
def get_default(self):
return Default()
class Invoice(models.Model):
...
number = AutoPositiveBigIntegerField(unique=True)
The above, coupled with the following manual migration on the number field:
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("billing", "0003_my_migration"),
]
operations = [
migrations.RunSQL(
"ALTER TABLE invoice ALTER COLUMN number ADD GENERATED BY DEFAULT AS IDENTITY;",
reverse_sql="ALTER TABLE invoice ALTER COLUMN number DROP IDENTITY IF EXISTS;"
),
]