# GeneratedField based on ID

**URL:** <https://forum.djangoproject.com/t/generatedfield-based-on-id/26502>\
**Category:** Using the ORM\
**Created:** [December 29, 2023, 1:38pm UTC](https://forum.djangoproject.com/t/generatedfield-based-on-id/26502 "2023-12-29T13:38:49Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![vazark](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/vazark/32/5827_2.png) [@vazark](https://forum.djangoproject.com/u/vazark)\
**Post date:** [December 29, 2023, 1:38pm UTC](https://forum.djangoproject.com/t/generatedfield-based-on-id/26502/1 "2023-12-29T13:38:49Z")

</div>

Hello,

I’m currently testing out the new GeneratedField functionality in 5.0. Has anyone had any success creating a field based on the ID? (for human-readable IDs inspired by stripe & django-spicy-id)

Here is what I’m trying (with little success). Any input to get it working would be cool

```python
human_id = models.GeneratedField(
        expression=Concat(
            models.Value("prefix_"),
            "id",
            output_field=models.CharField(),
        ),
        output_field=models.CharField(),
        db_persist=True,
    )

```

---

<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:** [December 29, 2023, 1:53pm UTC](https://forum.djangoproject.com/t/generatedfield-based-on-id/26502/2 "2023-12-29T13:53:34Z")

</div>

Which database engine are you using?

In the docs for [GeneratedField](https://docs.djangoproject.com/en/5.0/ref/models/fields/#django.db.models.GeneratedField.db_persist) there’s a note talking about how each different database engine puts different restrictions on what expressions are allowed. So check the appropriate docs to see if there are any issues with using an auto field in a `GeneratedField`.

Also, note that the [Concat](https://docs.djangoproject.com/en/5.0/ref/models/database-functions/#concat) docs specify:

> … Each argument must be of a text or char type. …

so trying to `Concat` an integer with a char field will not work. I think you may need to enclose that “id” column within a `Cast`.

---

<div class="post-metadata">

**Author:** ![vazark](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/vazark/32/5827_2.png) [@vazark](https://forum.djangoproject.com/u/vazark)\
**Post date:** [December 29, 2023, 2:18pm UTC](https://forum.djangoproject.com/t/generatedfield-based-on-id/26502/3 "2023-12-29T14:18:13Z")

</div>

Thanks for the redirect. Turns out that the concat function is not considered immutable on postgres. Switching to the operator with a touch of RawSQL got it working

Here’s what I used to get it working

```python
human_id = models.GeneratedField(
        expression=RawSQL("('prefix_' || id::text)",()),
        output_field=models.CharField(),
        db_persist=True,
    )

```

I guess I’ll stick with UUIDs for the moment. I had wanted to create a virtual field that has a human-readable ID that is built by encoding the integer IDs so that the lookup is just a decode + integer-based search (like django-spicy-id) but that looks like a difficult ask if dealing RawSQLs throughout the codebase

---

<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:** [December 29, 2023, 5:22pm UTC](https://forum.djangoproject.com/t/generatedfield-based-on-id/26502/4 "2023-12-29T17:22:56Z")

</div>

> [@vazark](#):
>
> if dealing RawSQLs throughout the codebase

I’m curious - why would you have raw SQL throughout the code base for this field?

You’ve created a real field that will contain the prefix and id that may look something like `prefix_123`. Everywhere else in your code you’ll be able to filter (or get) on `human_id="prefix_123"`.
