我想在创建特定django模型的实例时进行额外的初始化。我知道overriding __init__ can lead to trouble。我应该考虑哪些其他选择?
更新。其他详细信息:目的是初始化该模型实例所代表的状态机。这个状态机由一个导入的库提供,它的内部状态由我的django-model持久化。我们的想法是,无论何时加载模型,状态机都将使用模型的数据自动初始化。
答案 0 :(得分:16)
覆盖__init__
可能会有效,但这不是一个好主意,而且不是Django方式。
在Django中执行此操作的正确方法是使用signals。
在这种情况下您感兴趣的是pre_init
和post_init
。
django.db.models.signals.pre_init
每当你实例化Django时 模型,此信号在模型
__init__()
的开头发送 方法
django.db.models.signals.post_init
与
时pre_init
类似,但会发送此邮件 当__init__()
:方法完成
所以你的代码应该是
from django.db import models
from django.db.models.signals import post_init
class MyModel(models.Model):
# normal model definition...
def extraInitForMyModel(**kwargs):
instance = kwargs.get('instance')
do_whatever_you_need_with(instance)
post_init.connect(extraInitForMyModel, MyModel)
您也可以将信号连接到Django的预定义模型。
答案 1 :(得分:4)
docs中的两个建议方法依赖于以任意方式创建的实例:
在模型类上添加类方法:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
@classmethod
def create(cls, title):
book = cls(title=title)
# do something with the book
return book
book = Book.create("Pride and Prejudice")
在自定义管理器上添加方法:
class BookManager(models.Manager):
def create_book(self, title):
book = self.create(title=title)
# do something with the book
return book
class Book(models.Model):
title = models.CharField(max_length=100)
objects = BookManager()
book = Book.objects.create_book("Pride and Prejudice")
如果那是您的情况,我会那样做。如果没有,我会坚持使用@vartec的答案。
答案 2 :(得分:0)
虽然我同意通常有比覆盖__init__
更好的方法来进行您想做的事情,但有可能,并且在某些情况下它可能是有用的。
这是一个示例,该示例说明了如何正确覆盖模型的__init__
方法而又不干扰Django的内部逻辑:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# add your own logic