Django 5 update_or_create переворачивает поле один к одному

В Джанго 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,
    )


class Data(models.Model):
    pass

data, created = Data.objects.update_or_create(
            rough_project=project, defaults=data
        )    

В Джанго 5.x:

ValueError: The following fields do not exist in this model: rough_project

Я не вижу никаких изменений, связанных с этим, в журнале изменений

В Django 4.2 и ниже это работало одной строкой с update_or_create, а в 5.0 оно перестало работать, поэтому вместо этого мне нужно сделать что-то вроде этого:

data = getattr(project, "rough_data", None)
if data:
   # update fields here
else:
   # create Data object

Это то, что ты хотел сделать? data = Data.objects.get(project_set=project)

django.seolpyo.com 14.08.2024 02:18

Нет, я хочу сделать это: ``` data = getattr(project, "rough_project", None) if data: # обновить поля здесь else: # создать объект данных ``` В django 4.2 и ниже это работало как одна строка с update_or_create и в 5.0 он перестал работать. Я не понимаю, почему.

Arti 14.08.2024 10:25

Пожалуйста, укажите код в своем if else

Lord Elrond 15.08.2024 20:22
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В Django 4.x он не вызывал исключения, но и не сохранял связь, если объект был создан — так что на самом деле он работал не так, как ожидалось.

Кажется, что он работает так, как ожидалось, только если после этого вызывается project.save().

1Вы можете исправить это и вместо этого заранее сохранить отношения, создав подкласс QuerySet и переопределив метод create, а затем указав Dataobjects для использования вашего 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()

** Надеюсь, это поможет **

Другие вопросы по теме