# Slight modification to default \`\_\_repr\_\_\` for models?

**URL:** <https://forum.djangoproject.com/t/slight-modification-to-default-repr-for-models/35323>\
**Category:** Django Internals\
**Created:** [October 2, 2024, 6:25am UTC](https://forum.djangoproject.com/t/slight-modification-to-default-repr-for-models/35323 "2024-10-02T06:25:15Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![boxed](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/boxed/32/11975_2.png) [@boxed](https://forum.djangoproject.com/u/boxed)\
**Post date:** [October 2, 2024, 6:25am UTC](https://forum.djangoproject.com/t/slight-modification-to-default-repr-for-models/35323/1 "2024-10-02T06:25:15Z")

</div>

I was looking into an old issue about making `DoesNotExist` errors nicer ([Fixed #20278 -- ensured .get() exceptions do not recurse infinitely · django/django@266c0bb · GitHub](https://github.com/django/django/commit/266c0bb23e9d64c47ace4d162e582febd5a1e336#diff-d58ef61559dc7af5fdf7b56fee13571a4d2948e784cd608f6afeacf3ac2fb195R397)) which was reverted due to an infinite recursion, and I realized that the reason this problem occurs is because of another issue that I always patch in my projects: the default ` __repr__ ` on models calls ` __str__ `.

Current implementation:

```py
    def __repr__ (self):
        return "<%s: %s>" % (self. __class__. __name__ , self)

```

In all my projects I always have a common base class for my models that contain:

```py
    def __repr__ (self):
        return f'<{self. __class__. __name__ } pk={self.pk}>'

```

With this in place, the repr of an object won’t infinitely recurse by default, which means we can make `DoesNotExist` nicer.

A side not on this is that it’s also the case that the fix for DoesNotExist being reverted was because the error can end up in an infinite loop. But that’s also true for MultipleObjectsReturned. So logically we should either make DoesNotExist work or make MultipleObjectsReturned worse. I prefer the first 😛

---

<div class="post-metadata">

**Author:** ![boxed](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/boxed/32/11975_2.png) [@boxed](https://forum.djangoproject.com/u/boxed)\
**Post date:** [November 8, 2024, 7:17am UTC](https://forum.djangoproject.com/t/slight-modification-to-default-repr-for-models/35323/2 "2024-11-08T07:17:56Z")

</div>

I’ve thought about this some more. I think this change is good, but I ALSO think the `DoesNotExist` and `MultipleObjectsReturned` errors should NOT use `repr(obj)`, but instead use `Model. __repr__ (obj)` which (after this change) would guarantee that the error string can never recurse infinitely.

---

<div class="post-metadata">

**Author:** ![timgraham](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/timgraham/32/11972_2.png) [@timgraham](https://forum.djangoproject.com/u/timgraham)\
**Post date:** [November 8, 2024, 11:28am UTC](https://forum.djangoproject.com/t/slight-modification-to-default-repr-for-models/35323/3 "2024-11-08T11:28:35Z")

</div>

Past proposals to change `Model. __repr__ ()` have been rejected.

[https://code.djangoproject.com/ticket/20448](https://code.djangoproject.com/ticket/20448)  
[https://groups.google.com/g/django-developers/c/UNKFMg6DO5s/m/3nZECHyRAgAJ](https://groups.google.com/g/django-developers/c/UNKFMg6DO5s/m/3nZECHyRAgAJ)

[https://code.djangoproject.com/ticket/28839](https://code.djangoproject.com/ticket/28839)  
[https://groups.google.com/g/django-developers/c/7Jqzwg5nt-c/m/oYxx9CgBBQAJ](https://groups.google.com/g/django-developers/c/7Jqzwg5nt-c/m/oYxx9CgBBQAJ)

[https://groups.google.com/g/django-developers/c/4yd8wBD3BiY/m/139xyLaEBAAJ](https://groups.google.com/g/django-developers/c/4yd8wBD3BiY/m/139xyLaEBAAJ)

---

<div class="post-metadata">

**Author:** ![boxed](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/boxed/32/11975_2.png) [@boxed](https://forum.djangoproject.com/u/boxed)\
**Post date:** [November 8, 2024, 12:25pm UTC](https://forum.djangoproject.com/t/slight-modification-to-default-repr-for-models/35323/4 "2024-11-08T12:25:17Z")

</div>

Well… sort of.

1. super old, and really talks about a different situation before the pk was included
2. closed as already fixed, so not really relevant
3. Adam points out that this is _already the default_ if you don’t override ` __str__ `, which is my point. If you DO override it you will potentially shoot yourself in the foot very badly. (Fun fact, it was me who Fabian talks about on the mailing list, it was my suggestion to him :P)

---

<div class="post-metadata">

**Author:** ![boxed](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/boxed/32/11975_2.png) [@boxed](https://forum.djangoproject.com/u/boxed)\
**Post date:** [February 6, 2025, 1:25pm UTC](https://forum.djangoproject.com/t/slight-modification-to-default-repr-for-models/35323/5 "2025-02-06T13:25:10Z")

</div>

I thought a bit more about this and I have a different suggestion:

Introduce a new function `safe_repr` that does ONLY `<{class_name} pk={pk}>`, then use that internally for `DoesNotExist` and `MultipleObjectsReturned`. This will fix the issues where users can accidentally shoot themselves in the foot, and not have any backwards incompatibility problems as far as I can see.

It would also mean that we can finally fix these error messages.
