Может ли Django автоматически создавать связанную модель "один-к-одному"?
У меня две модели в разных приложениях: modelA и modelB. У них есть отношения "один к одному". Есть ли способ, которым django может автоматически создавать и сохранять ModelB при сохранении modelA?
class ModelA(models.Model):
name = models.CharField(max_length=30)
class ModelB(models.Model):
thing = models.OneToOneField(ModelA, primary_key=True)
num_widgets = IntegerField(default=0)
Когда я сохраняю новый ModelA, я хочу, чтобы запись автоматически сохранялась в ModelB. Как я могу это сделать? Есть ли способ указать это в ModelA? Или это невозможно, и мне просто нужно создать и сохранить ModelB в представлении?
Отредактировано, что модели находятся в разных приложениях.
Ответы
Ответ 1
Взгляните на AutoOneToOneField в django-annoying. Из документов:
from annoying.fields import AutoOneToOneField
class MyProfile(models.Model):
user = AutoOneToOneField(User, primary_key=True)
home_page = models.URLField(max_length=255)
icq = models.CharField(max_length=255)
(django-annoying - это небольшая библиотека, которая включает в себя такие драгоценные камни, как декоратор render_to и функции get_object_or_None и get_config)
Ответ 2
Как указано в m000, ваши модели существуют в разных приложениях. Часто вы используете приложения, которые вы не пишете, поэтому для обеспечения обновлений вам нужен развязанный способ создания логически связанных моделей. Это предпочтительное решение, на мой взгляд, и мы используем его в очень большом проекте.
Используя сигналы:
В ваших models.py:
from django.db.models import signals
def create_model_b(sender, instance, created, **kwargs):
"""Create ModelB for every new ModelA."""
if created:
ModelB.objects.create(thing=instance)
signals.post_save.connect(create_model_b, sender=ModelA, weak=False,
dispatch_uid='models.create_model_b')
Вы можете создать отдельное приложение для хранения этого файла models.py, если оба приложения находятся в готовом виде.
Ответ 3
Самый простой способ - переопределить метод сохранения ModelA:
class ModelA(models.Model):
name = models.CharField(max_length=30)
def save(self, force_insert=False, force_update=False):
is_new = self.id is None
super(ModelA, self).save(force_insert, force_update)
if is_new:
ModelB.objects.create(thing=self)
Ответ 4
Я думаю, вы хотите использовать наследование модели django. Это полезно, если вы выполняете следующее утверждение: ModelA - это ModelB (например, "Ресторан - это местоположение" ).
Вы можете определить:
class ModelB(models.Model):
field1 = models.CharField(...)
class ModelA(ModelB):
field2 = models.CharField(...)
Теперь вы можете создать экземпляр ModelA и задать поле2 и поле1. Если эта модель будет сохранена, она также создаст экземпляр ModelB, который получит значение field1. Все это делается прозрачно за кулисами.
Хотя вы можете сделать следующее:
a1 = ModelA()
a1.field1 = "foo"
a1.field2 = "bar"
a1.save()
a2 = ModelA.objects.get(id=a1.id)
a2.field1 == "foo" # is True
a2.field2 == "bar" # is True
b1 = ModelB.objects.get(id=a1.id)
b1.field1 == "foo" # is True
# b1.field2 is not defined
Ответ 5
Я знаю это немного позже, но я придумал более чистое и элегантное решение.
Рассмотрим этот код:
class ModelA(models.Model):
name = models.CharField(max_length=30)
@classmethod
def get_new(cls):
return cls.objects.create().id
class ModelB(models.Model):
thing = models.OneToOneField(ModelA, primary_key=True, default=ModelA.get_new)
num_widgets = IntegerField(default=0)
Конечно, вы можете использовать лямбда, если вы возвращаете целочисленный идентификатор связанного объекта:)
Ответ 6
Вы можете использовать post_save-hook, который запускается после сохранения записи. Дополнительную документацию по сигналам django см. Здесь здесь. На на этой странице вы найдете пример того, как применить крючок к вашей модели.
Ответ 7
Просто создайте функцию, которая создает и возвращает пустой ModelA, и задает по умолчанию аргумент по умолчанию для "вещи".