【问题标题】:Adding to the "constructor" of a django model添加到 django 模型的“构造函数”
【发布时间】:2012-02-23 15:08:33
【问题描述】:

每当创建特定 django 模型的实例时,我都想进行额外的初始化。我知道overriding __init__ can lead to trouble。我应该考虑哪些其他替代方案?

更新。其他详细信息: 目的是初始化该模型的实例所代表的状态机。这个状态机由一个导入的库提供,它的内部状态由我的 django-model 持久化。这个想法是,每当加载模型时,状态机都会自动使用模型的数据进行初始化。

【问题讨论】:

  • 你误解了这个问题。这并不是说覆盖__init__ 不起作用,OP 只是做错了。您可以随意覆盖__init__,但其效果完全取决于您到底想要做什么。所以你为什么不告诉我们,这样我们才能真正帮助你。
  • 谢谢,我已经重读了另一个线程。你的意思是,如果我保留签名 (self, *args, **kwargs),覆盖 __init__ 就不会影响 django 的方式?
  • 我在问题中添加了更多信息以阐明意图。

标签: django django-models


【解决方案1】:

虽然我同意通常有比覆盖 __init__ 更好的方法来完成您想要做的事情,但这是可能的,并且在某些情况下它可能有用。

下面是一个示例,说明如何在不干扰 Django 内部逻辑的情况下正确覆盖模型的 __init__ 方法:

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

【讨论】:

    【解决方案2】:

    docs 中建议的两个方法依赖于以任意方式创建的实例:

    1. 在模型类上添加classmethod:

      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")
      
    2. 在自定义管理器上添加方法:

      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 的回答。

    【讨论】:

    • 是否有经验法则可以根据上下文知道哪种方法比另一种更合适?
    【解决方案3】:

    覆盖__init__ 可能有效,但这是个坏主意,而且不是 Django 的方式。

    在 Django 中正确的做法是使用signals

    在这种情况下,您感兴趣的是pre_initpost_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 的预定义模型。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-16
    • 2013-11-09
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多