Django 5 update_or_create обратный переход от одного к другому полю
На Django 4.x
Код работает так, как ожидалось
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,
)
data, created = Data.objects.update_or_create(
rough_project=project, defaults=data
)
На Django 5.x:
ValueError: The following fields do not exist in this model: rough_project
Я не вижу никаких изменений, связанных с этим, в changelog
В Django 4.x он не вызывал исключения, но и не сохранял отношения, если объект был создан - так что на самом деле не работал так, как ожидалось.
- Django ticket: https://code.djangoproject.com/ticket/34586
- Django PR that fixed1 it to raise exception: https://github.com/django/django/pull/17112/files
Похоже, работает так, как ожидалось, только если после этого вызывается project.save()
.
1 Вы можете исправить это, чтобы проактивно сохранять отношения, подклассифицировав QuerySet
и переопределив метод create
, а затем указав Data
objects
для использования вашего 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()
Я думаю, что это проблема модели:
Внутри модели данных нет ни одного поля rough_project
Приведенный вами код не будет работать так, как нужно, из-за того, что update_or_create используется с OneToOneField.
Поиск rough_project=project
пытается найти объект Data
, где обратное отношение rough_project
указывает на объект Project
. Однако rough_project
является обратным отношением в модели Data
, а Django не позволяет использовать обратные отношения в части поиска update_or_create
.
Если вы хотите обновить или создать объект Data
и связать его с объектом Project
, вам нужно сделать примерно следующее:
data, created = Data.objects.update_or_create(
id=some_id, # Use an appropriate field to identify the Data object, e.g., primary key (id).
defaults={'rough_project': project} # Correctly specify the relationship in defaults.
)
Если у вас есть экземпляр Project
и вы хотите установить его rough_data
или final_data
:
# Create or get the Data object
data, created = Data.objects.update_or_create(
id=some_id, # some unique identifier for Data
defaults={'some_field': some_value} # other fields to update or set
)
# Assign the Data object to the Project
project.rough_data = data
project.save()
** Надеюсь, это поможет **