【问题标题】:Why does adding this __init__() method break my Django model?为什么添加这个 __init__() 方法会破坏我的 Django 模型?
【发布时间】:2016-06-14 02:29:04
【问题描述】:

这个问题是我之前问的here 的后续问题。

我有一个 Django 模型如下:

class MyModel(models.Model):
    my_field1 = models.DateTimeField(default=datetime.utcnow, editable=False)
    my_field2 = models.DateTimeField()

有效:

>>> MyModel.objects.all()
[<MyModel: MyModel object>, <MyModel: MyModel object>,

现在我将以下构造函数添加到MyModel

def __init__(self, **kwargs):
    super(MyModel, self).__init__(**kwargs)
    if self.my_field2 is None:
        self.my_field2 = self.my_field1

这打破了课堂:

>>> MyModel.objects.all()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "MYvirtualenv/lib/python2.7/site-packages/django/db/models/query.py", line 138, in __repr__
    data = list(self[:REPR_OUTPUT_SIZE + 1])
  File "MYvirtualenv/lib/python2.7/site-packages/django/db/models/query.py", line 162, in __iter__
    self._fetch_all()
  File "MYvirtualenv/lib/python2.7/site-packages/django/db/models/query.py", line 965, in _fetch_all
    self._result_cache = list(self.iterator())
  File "MYvirtualenv/src/django-cache-machine-master/caching/base.py", line 118, in __iter__
    obj = iterator.next()
  File "MYvirtualenv/lib/python2.7/site-packages/django/db/models/query.py", line 255, in iterator
    obj = model_cls.from_db(db, init_list, row[model_fields_start:model_fields_end])
  File "MYvirtualenv/lib/python2.7/site-packages/django/db/models/base.py", line 489, in from_db
    new = cls(*values)
TypeError: __init__() takes exactly 1 argument (2 given)

当我添加相对简单的构造函数时,为什么会发生这种情况?我该如何补救?我需要那个构造函数中的逻辑,所以我不能直接消除它。

【问题讨论】:

  • 你在任何地方都有MyModel,但在构造函数中却有Prediction。您只是忘记对其进行消毒还是实际上是不小心调用了错误的课程?
  • 听起来您缺少参数。 def __init__(self, *args, **kwargs)
  • @Anonymous。是的。那是一个卫生错误。对不起。现已修复。
  • 参见stackoverflow.com/questions/843580/… 进行类似讨论。
  • 不要使用 init 我已经为你的其他问题添加了答案。

标签: python django constructor


【解决方案1】:

尽管强烈建议您在文档中使用 classmethod 或自定义管理器,但您的代码将无法正常工作,因为您修改了 superclass 的调用签名,它应该是:

super(MyModel, self).__init__(*args, **kwargs)

您可以使用classmethod 避免这样做:

class MyModel(models.Model):
    my_field1 = models.DateTimeField(default=datetime.utcnow, editable=False)
    my_field2 = models.DateTimeField()

    @classmethod
    def sync_dates(cls, myfield1):
         my_model = cls(my_field1=myfield1, my_field2=myfield1)
         # do something with my_model
         return my_model

MyModel.sync_dates(some_date) 可以解决问题。

或者您可以使用自定义管理器,这是首选方式:

class MyModelManager(models.Manager):
    def create_with_sync_date(self, myfield1):
        my_model = self.create(my_field1=myfield1, my_field2=myfield1)
        # do something with my_model
        return my_model

class MyModel(models.Model):
    my_field1 = models.DateTimeField(default=datetime.utcnow, editable=False)
    my_field2 = models.DateTimeField()

    objects_synced = MyModelManager()

您可以拨打MyModel.objects_synced.create_with_sync_date(some_date)

【讨论】:

    【解决方案2】:

    不鼓励使用 init。 根据 Django 文档:

    https://docs.djangoproject.com/en/1.9/ref/models/instances/#creating-objects

    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")
    

    【讨论】:

      【解决方案3】:

      你不需要在Django模型中使用__init__,而是使用Meta

      class MyModel(models.Model):
          my_field1 = models.DateTimeField(default=datetime.utcnow, editable=False)
          my_field2 = models.DateTimeField()
      
          class Meta:
              verbose_name = 'My Model'
              verbose_name_plural = 'My Models' # and so on
      

      【讨论】:

      • 这与我展示的__init__() 方法的功能不同。
      猜你喜欢
      • 2019-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多