# Non-primary key database sequence

**URL:** <https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736>\
**Category:** Using the ORM\
**Created:** [May 5, 2023, 1:27pm UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736 "2023-05-05T13:27:30Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/tom/32/6818_2.png) [@tom](https://forum.djangoproject.com/u/tom)\
**Post date:** [May 5, 2023, 1:27pm UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736/1 "2023-05-05T13:27:30Z")

</div>

AutoField has to have a primary key, but I have a column we want to increment. It’s a kind of account ID that we want to generate, but we don’t want to have them as the primary key as it’s a bit inflexible if we want to change the scheme at some point in the future, and at the moment all our models have UUIDs for PKs, which seems unnecessary to me but it’s what we have.

As we’re running Postgres we should be able to just have an extra identity field and I don’t mind create a new model Field class to do this… I am just wondering if this is going to break something somewhere? Presumably there’s some reason AutoFields have to be the primary key but I couldn’t surface much information up on it or if having a custom field class would bypass these issues.

Does anyone have an idea? Or if there’s a better solution to this problem I’m not thinking of?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [May 5, 2023, 1:40pm UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736/2 "2023-05-05T13:40:34Z")

</div>

We had a similar situation - what we had done was create the [SERIAL column](https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL) directly in the database using SQL, and defined the field in the model as an IntegerField. (If we had to do it again, we’d probably define the field as a custom migration.)

---

<div class="post-metadata">

**Author:** ![grandimam](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/grandimam/32/20953_2.png) [@grandimam](https://forum.djangoproject.com/u/grandimam)\
**Post date:** [April 29, 2024, 3:53pm UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736/3 "2024-04-29T15:53:20Z")

</div>

We are also looking to do something similar. We created a custom migration script that does the creates a column short\_url\_ref in our model. However, what I don’t understand is that you said you defined the field in the model as an IntegerField - is it like a place holder or do you run migration again:

`python manage.py makemigrations`

This is my migration script, is there anything additional you are doing from your side. Because I am seeing that if I do `makemigrations` then django asks me to provide a default value etc.

```auto
def add_short_url_ref_field(apps, schema_editor):
    connection = schema_editor.connection
    with connection.cursor() as cursor:
            cursor.execute(
                'PRAGMA table_info({});'.format(connection.ops.quote_name(model._meta.db_table))
            )
            columns = cursor.fetchall()
            column_exists = any(column[1] == 'short_url_ref' for column in columns)
            if not column_exists:
                cursor.execute(
                    'ALTER TABLE {} ADD COLUMN short_url_ref SERIAL;'
                    .format(connection.ops.quote_name(model._meta.db_table))
                )

class Migration(migrations.Migration):
    dependencies = [
        ('', ''),
    ]

    operations = [
        migrations.RunPython(add_short_url_ref_field, reverse_code=remove_short_url_ref_field),
    ]

```

Your help would be appreciated here!

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/tom/32/6818_2.png) [@tom](https://forum.djangoproject.com/u/tom)\
**Post date:** [April 29, 2024, 4:31pm UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736/4 "2024-04-29T16:31:49Z")

</div>

There is another possibility mentioned here: [Django 4.2, is a 2nd autofield-like field on a model possible? - #4 by jaddison](https://forum.djangoproject.com/t/django-4-2-is-a-2nd-autofield-like-field-on-a-model-possible/28278/4)

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 29, 2024, 4:44pm UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736/5 "2024-04-29T16:44:29Z")

</div>

> [@grandimam](#):
>
> However, what I don’t understand is that you said you defined the field in the model as an IntegerField - is it like a place holder or do you run migration again:

Yes, we ran `makemigrations`, primarily to ensure that Django knows that the models match the database. But since we’ve already created the field in the model _and_ the column in the database, we ran `migrate --fake` for it. That makes the definition of a default pretty much irrelevant.

Having said that, if we were to find ourselves in a similar situation _now_, we’d probably take a look at the approach in the thread that Tom references above.

---

<div class="post-metadata">

**Author:** ![grandimam](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/grandimam/32/20953_2.png) [@grandimam](https://forum.djangoproject.com/u/grandimam)\
**Post date:** [April 29, 2024, 5:09pm UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736/6 "2024-04-29T17:09:29Z")

</div>

When you ran make migrations didn’t Django complain about IntegerField() being non-nullable? When I run `makemigrations` I get a prompt asking to define the field as nullable - which in turn creates another migration script that adds the field. If it’s not too much to ask it would be really helpful if you could share me the steps to that you took?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 29, 2024, 5:50pm UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736/7 "2024-04-29T17:50:51Z")

</div>

> [@grandimam](#):
>
> When you ran make migrations didn’t Django complain about IntegerField() being non-nullable?

Honestly, I don’t recall. Regardless, it didn’t matter because the migrate was run with the `--fake` parameter, which meant that nothing in the migration was going to be performed anyway.

---

<div class="post-metadata">

**Author:** ![quertenmont](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/quertenmont/32/20580_2.png) [@quertenmont](https://forum.djangoproject.com/u/quertenmont)\
**Post date:** [August 14, 2024, 1:33am UTC](https://forum.djangoproject.com/t/non-primary-key-database-sequence/20736/8 "2024-08-14T01:33:26Z")

</div>

I developed django-sequencefield that address exactly that case:

> **[GitHub - quertenmont/django-sequencefield: Additional field from django taking it's value...](https://github.com/quertenmont/django-sequencefield)**
>
> Additional field from django taking it's value from a postgresql sequence. It is similar to django AutoField, except that multiple model can share ids from a single sequence

It’s now easy to add as many field as you want taking their values from a postgresql sequence. The sequence is created through a migration. The sequence can be shared through multiple tables which is also pretty useful in some cases
