Почему метод create в моем пользовательском менеджере не работает?
Я пытаюсь создать пользовательский менеджер для класса model в моем проекте Django.
Классы моделей Story и Plot имеют взаимно однозначную связь. Я хочу, чтобы новый экземпляр Plot создавался автоматически при создании нового экземпляра Story. Прямо сейчас я делаю это с помощью функции просмотра, но при тестировании создания объекта Story без функции просмотра это не удается.
Я знаю, что есть несколько способов добиться этого, но я решил использовать пользовательский менеджер, чтобы добавить эту логику после создания, переопределив метод objects.create. Соответствующий код приведен ниже:
class Story(models.Model):
... other fields
objects = models.Manager()
class Plot(models.Model):
... other fields
story = models.OneToOneField(Story, on_delete=models.CASCADE, null=True, default=None, related_name='plot')
class StoryManager(models.Manager):
def create(self, **kwargs):
story = super().create(**kwargs)
plot = Plot.objects.create(
... other kwargs,
story_id=story.id
)
return story
# Assign the story manager to the Story model
Story.objects = StoryManager()
Теперь я получаю следующую обратную трассировку при выполнении тестов, использующих метод Story.objects.create:
File "C:\Users\jacob\documents\programming\story-builder\storybuilder\app\models.py", line 221, in create
story = super().create(**kwargs)
File "C:\Users\jacob\documents\programming\story-builder\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "C:\Users\jacob\documents\programming\story-builder\.venv\Lib\site-packages\django\db\models\query.py", line 669, in create
self.model._meta._reverse_one_to_one_field_names
^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute '_meta'
Я новичок в концепции ORM Django и в том, как она работает под капотом, поэтому, возможно, это даже не рекомендуемый способ автоматического создания объекта при создании другого объекта. В своих исследованиях, проведенных до сих пор, я встречал рекомендации по переопределению метода сохранения первой модели, что нецелесообразно, поскольку метод сохранения определен перед соответствующим классом модели.
Я также рассматривал возможность использования сигнала post_save, но у меня сложилось впечатление, что у него много потенциальных побочных эффектов, которые трудно отлаживать, и что в большинстве случаев лучше использовать такой вариант, как создание пользовательского менеджера.
Но о чем вы думаете?
Я полагаю, что это из-за вашего странного исправления атрибута objects
. Он должен использовать диспетчер по умолчанию, пока не будет исправлен. Если сделать это правильно, это просто сработает:
class StoryManager(models.Manager):
def create(self, **kwargs):
story = super().create(**kwargs)
Plot.objects.create(story_id=story.id)
return story
class Story(models.Model):
objects = StoryManager()
class Plot(models.Model):
story = models.OneToOneField(
Story, on_delete=models.CASCADE, null=True, default=None, related_name="plot"
)
Я полагаю, что это из-за вашего странного исправления атрибута objects
. Он должен использовать диспетчер по умолчанию, пока не будет исправлен. Если сделать это правильно, это просто сработает:
class StoryManager(models.Manager):
def create(self, **kwargs):
story = super().create(**kwargs)
Plot.objects.create(story_id=story.id)
return story
class Story(models.Model):
objects = StoryManager()
class Plot(models.Model):
story = models.OneToOneField(
Story, on_delete=models.CASCADE, null=True, default=None, related_name="plot"
)
tests.py
class TestStory(TestCase):
def test_story(self):
story = Story.objects.create()
self.assertEqual(story.plot.story, story)