On Django 4.x
Code is working as expected
from django.db import models
class Project(models.Model):
rough_data = models.OneToOneField(
"Data",
related_name="rough_project",
on_delete=models.SET_NULL,
null=True,
blank=True,
)
final_data = models.OneToOneField(
"Data",
related_name="final_project",
on_delete=models.SET_NULL,
null=True,
blank=True,
)
class Data(models.Model):
pass
data, created = Data.objects.update_or_create(
rough_project=project, defaults=data
)
On Django 5.x:
ValueError: The following fields do not exist in this model: rough_project
I do not see any changes related to this in changelog
In Django 4.2 and below it worked as one line with update_or_create
and in 5.0 it stopped working, so instead I need to do something like this:
data = getattr(project, "rough_data", None)
if data:
# update fields here
else:
# create Data object
In Django 4.x, it did not raise an exception but also did not save the relationship if the object was created — so it was actually not working as expected.
It appears to work as expected only if project.save()
is called afterwards.
1You could fix it to proactively save the relationship instead, by subclassing QuerySet
and overriding the create
method, and then specifying Data
objects
to use your Manager
:
class CreateSaveReverseOneToOneFieldsQuerySet(models.QuerySet):
def create(self, **kwargs):
"""
Create a new object with the given kwargs, saving it to the database and returning the created object.
Also save objects in reverse OneToOne fields — see https://stackoverflow.com/questions/78863608/django-5-update-or-create-reverse-one-to-one-field.
"""
obj = self.model(**kwargs)
self._for_write = True
obj.save(force_insert=True, using=self.db)
# Save reverse OneToOne fields
reverse_one_to_one_fields = frozenset(kwargs).intersection(self.model._meta._reverse_one_to_one_field_names)
for field_name in reverse_one_to_one_fields:
getattr(obj, field_name).save()
return obj
class DataManager(models.manager.BaseManager.from_queryset(CreateSaveReverseOneToOneFieldsQuerySet)):
pass
class Data(models.Model):
objects = DataManager()