Добавяне на автоматично поле за непървичен ключ или „серийно“ поле в модел на Django, който използва UUID поле като основно поле

Изграждам модел с UUIDField като първичен ключ. Но моят случай на употреба изисква. има и поле за автоматично нарастване. Django предоставя AutoField. Но се изисква да има primary_key=True, което в моя случай е нещо, което не искам, тъй като използвам UUIDField като primary_key.

Опитах да създам поле и дадох db_type на 'serial' и добавих миграция, която променя последователността да се рестартира на 100 000.. Добавянето на обект към базата данни с помощта на Admin винаги ще съхранява числовото поле като нулева стойност. и ако премахна null=True. Тогава запазването ще се провали, тъй като ще изисква стойност за числовото поле.

Как мога да направя числовото поле инкрементално, като същевременно запазя UUIDField като първичен ключ?

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 от django.db импортиране на миграции

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)
    ]

person Basel J. Hamadeh    schedule 24.03.2018    source източник
comment
Нямам отговор, но можете да видите част от хронологията в този билет ( въпреки че дискусията е предимно за наличието на множество AutoFields). Съгласен съм, че това не е правилно документирано.   -  person Kevin Christopher Henry    schedule 24.03.2018


Отговори (2)


Опитах и ​​това. Моето решение беше вместо това да използвам необработен SQL.

миграция:

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

Модел:

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)
person SebastianR    schedule 06.03.2019

За пример, нека приемем, че името на нашата таблица е изплащания

По-долу ще бъде даден моделът за изплащания:

class Payouts(models.Model):
    # seq_id = models.IntegerField() 
    # we will create seq_id auto-increment by raw SQL
    id = models.UUIDField(primary_key=True)

    class Meta:
        managed = True
        db_table = 'payouts'

Можете да видите, че искаме да имаме id с uuid като първичен ключ.

Следвайте инструкциите по-долу:

Стъпка 1: Направете файл за миграции за модела по-горе.

python manage.py makemigrations

Стъпка 2: Генерирайте празна миграция за изпълнение на SQL заявки:

python manage.py makemigrations  --empty -n dont_delete_add_defaults_sql

Стъпка 3: Редактирайте dont_delete_add_defaults_sql както е показано по-долу:

from django.db import migrations    

class Migration(migrations.Migration):

    dependencies = [
        ('apiapp', '0001_initial'), #Replace 0001_initial with the name of file generated in step 1
    ]

    operations = [
        migrations.RunSQL("ALTER TABLE payouts ADD seq_id serial NOT NULL;"),
        migrations.RunSQL("DROP SEQUENCE IF EXISTS payouts_seq_id_seq CASCADE;"),
        migrations.RunSQL("create sequence payouts_seq_id_seq owned by payouts.seq_id;"),
        migrations.RunSQL("alter table payouts alter column seq_id set default nextval('payouts_seq_id_seq');"),
    ]

Стъпка 4: Изпълнете окончателните миграции

python manage.py migrate
person user3785966    schedule 08.12.2019