[Django] #35729: How to serialize user profiles without natural keys?

11 views
Skip to first unread message

Django

unread,
Sep 2, 2024, 3:16:20 PM9/2/24
to django-...@googlegroups.com
#35729: How to serialize user profiles without natural keys?
--------------------------------+-----------------------------------------
Reporter: Jonas Dittrich | Type: Uncategorized
Status: new | Component: Uncategorized
Version: 5.1 | Severity: Normal
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+-----------------------------------------
We want to have a custom UserProfile that inherits from AbstractBaseUser
without the need to define a natural key. There should be a nice way to do
this.

Our custom UserProfile inherits from AbstractBaseUser. We don't have any
possible unique field combination that we could use as a `natural_key`.
(Our `USERNAME_FIELD` is not unique. It's an email that might be NULL for
multiple users)

When dumping data, we want to use `natural_foreign=True` and
`natural_primary=True` matching the
documentation recommendations, see
https://docs.djangoproject.com/en/5.1/topics/serialization/#natural-keys.

Now, `AbstractBaseUser` defines the `natural_key` function to return the
value of `USERNAME_FIELD` and there doesn't seem to be an alternative
implementation in our derived class.

Is there a way to dump our data using `natural_foreign=True` and
`natural_primary=True` without serializing the user profile with natural
keys?

What we tried so far:
- making natural_key just return `(pk,)`. This does not work. The pk of
the user profile is not serialized because the model defines `natural_key`
and django excludes the pk from the list of dumped fields when a
`natural_key` exists, see
https://github.com/django/django/blob/c6a4f853c7167c1001761dcff30d7a64690e8236/django/core/serializers/python.py#L37.
- overwriting `__getattribute__` on the user profile, raising an
`AttributeError` when `natural_key` is requested. M2M fields call
`hasattr` on the class, not on the instance which has the modified
`__getattribute__` function.
- trying to delete the `natural_key` function from our user profile class
using `del` and `delattr`. `hasattr` finds the function from the
superclass; our user profile does not define the `natural_key` function.

Basically the problem is that removing the `natural_key` function from the
child class violates Liskov's substitution principle.

In theory, we could `del AbstractBaseUser.natural_key` but this deeply
interferes with Django; we don't want to do that.
--
Ticket URL: <https://code.djangoproject.com/ticket/35729>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Sep 2, 2024, 5:30:55 PM9/2/24
to django-...@googlegroups.com
#35729: How to serialize user profiles without natural keys?
--------------------------------+--------------------------------------
Reporter: Jonas Dittrich | Owner: (none)
Type: New feature | Status: closed
Component: contrib.auth | Version: dev
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------
Changes (by Natalia Bidart):

* component: Uncategorized => contrib.auth
* resolution: => invalid
* status: new => closed
* type: Uncategorized => New feature
* version: 5.1 => dev

Comment:

Hello Jonas, thank you for your ticket!

This report seems better suited to be a support request. The best place to
get answers to your issue is using any of the user support channels from
[https://docs.djangoproject.com/en/dev/faq/help/#how-do-i-do-x-why-
doesn-t-y-work-where-can-i-go-to-get-help this link].

Since the goal of this issue tracker is to track issues about Django
itself, and this report is about how to use Django for a specific niche
need, I'll be closing this ticket as `invalid` following the
[https://docs.djangoproject.com/en/dev/internals/contributing/triaging-
tickets/#closing-tickets ticket triaging process]. If, after debugging or
further conversations in the forum, you find out that this is indeed a bug
in Django, please re-open with the specific details and please be sure to
include a small Django project to reproduce or a failing test case.
--
Ticket URL: <https://code.djangoproject.com/ticket/35729#comment:1>

Django

unread,
Sep 25, 2025, 11:11:07 AM9/25/25
to django-...@googlegroups.com
#35729: How to serialize user profiles without natural keys?
--------------------------------------+------------------------------------
Reporter: Jonas Dittrich | Owner: (none)
Type: Bug | Status: closed
Component: Core (Serialization) | Version: dev
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------------+------------------------------------
Changes (by Jacob Walls):

* component: contrib.auth => Core (Serialization)
* stage: Unreviewed => Accepted
* type: New feature => Bug

Comment:

After further discussion on the [https://forum.djangoproject.com/t/how-to-
serialize-user-profiles-without-natural-keys/34447 forum], and in a
related ticket (#36225), I agree this is a usability bug in the
serialization framework. The user model aspect is just orthogonal.

Django's pattern of calling `hasattr(obj, "natural_key")` is not subclass-
friendly as pointed out above. There needs to be some way to ''cancel''
natural key serialization in a subclass and check for that. Maybe `def
natural_key() -> tuple[str]` becomes `def natural_key() => tuple[str] |
None`, and `hasattr(obj, "natural_key")` becomes `getattr(obj,
"natural_key", None) is not None`?
--
Ticket URL: <https://code.djangoproject.com/ticket/35729#comment:2>
Reply all
Reply to author
Forward
0 new messages