Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a Non-Primary Key AutoField or a 'serial' field in a Django Model which uses a UUID field as a Primary Field

I am building a Model with a UUIDField as the Primary Key. But my use case requires. having an Auto Increment field as well. Django provides an AutoField. But it is required to have primary_key=True which in my case something I don't want as I am using the UUIDField as primary_key.

I tried creating a field and giving db_type of 'serial' and adding a migration which alters the sequence to restart at 100000.. Adding an object to the database using the Admin will always store the number field as null value. and if I remove null=True. Then the save will fail as it will require a value for the number field.

How can I make the number field incremental while keeping the UUIDField as a primary key ?

fields.py

class SerialField(models.Field):
    description = _("BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE")

    empty_strings_allowed = False

    default_error_messages = {
        'invalid': _("'%(value)s' value must be an integer."),
    }

    def __init__(self, *args, **kwargs):
        kwargs['blank'] = True
        super().__init__(*args, **kwargs)

    def db_type(self, connection):
        return 'serial'

models.py

from .fields import SerialField

class MyModel(models.Model):
    uuid = models.UUIDField(
        verbose_name=_("UUID Identifier"),
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
        help_text=_("Requried, PrimaryKey none-editable"),
        db_index=True,
    )
    number = SerialField(
        primary_key=False,
        editable=False,
        help_text=_("Auto Increment Number"),
        verbose_name=_("Number"),
        #null=True
    )

0002_auto_20180202.py from django.db import migrations

def forwards(apps, schema_editor):
    if schema_editor.connection.alias == 'default':
        return migrations.RunSQL(
            "ALTER SEQUENCE app_name_mymodel_number_seq RESTART WITH 100000"
        )


class Migration(migrations.Migration):

    dependencies = [
        ('activities', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(forwards)
    ]
like image 350
Basel J. Hamadeh Avatar asked Mar 24 '18 05:03

Basel J. Hamadeh


1 Answers

Tried this as well. My workaround was to use raw SQL instead.

Migration:

migrations.RunSQL(
    "CREATE SEQUENCE sequence_name START 100000",
    reverse_sql="DROP SEQUENCE IF EXISTS sequence_name",
    elidable=False,
),

Model:

def get_next_increment():
    with connection.cursor() as cursor:
        cursor.execute("SELECT nextval('sequence_name')")
        result = cursor.fetchone()
        return result[0]

class MyModel(models.Model):
    my_field = models.IntegerField(default=get_next_increment, editable=False, unique=True)
like image 154
SebastianR Avatar answered Nov 02 '22 08:11

SebastianR