Issue: Peewee calls __init__ on model unexpectedly
Author: jrs65
State: closed
Created: 2016-02-16 22:10:12

We've run into some trouble when upgrading to peewee 2.8.0, when we have a custom `__init__` defined on our models. This behaviour worked fine when on earlier versions (2.7.3 is the other version I tested).

``` python
import peewee as pw

db = pw.SqliteDatabase(':memory:')


class TestTable1(pw.Model):

    a = pw.IntegerField()
    b = pw.IntegerField(default=2)

    class Meta:
        database = db


class TestTable2(pw.Model):

    def __init__(self, a=2):
        pw.Model.__init__(self, a=a)

    a = pw.IntegerField()
    b = pw.IntegerField(default=2)

    class Meta:
        database = db


db.connect()

db.create_tables([TestTable1, TestTable2])

# This works fine
TestTable1.create(a=2)
t1 = TestTable1.select().get()

# This fails
TestTable2.create(a=2)
t2 = TestTable2.select().get()  # Failure with: TypeError: __init__() got an unexpected keyword argument 'b'
```

In the code above, the failure occurs in the final select, it seems that when the model instance is created, the code in `playhouse._speedups._ModelQueryResultWrapper.process_row` uses `__init__` to create an instance of the row with the full results of the query passed as kwargs (i.e. a=2, b=2). However, the `TestTable2.__init__` does not support `b` as a keyword argument.

It's not clear from the documentation how well I should expect custom `__init__` methods to work. However, I would imagine that this could be fixed by making `playhouse._speedups._ModelQueryResultWrapper.process_row` explicitly call `pw.Model.__init__` on an instance created via `__new__`.


Try modifying your `__init__` to:

```
def __init__(self, a=2, **kwargs):
    pw.Model.__init__(self, a=a, **kwargs)
```


@lez is correct. Models that override `__init__()` should accept arbitrary kwargs and pass them to the parent constructor. Really, you should not be overriding `__init__()` in the first place though.


Thanks. I guess my confusion came from the fact this used to work fine on earlier versions.

Might be worth a mention in the documentation about not overriding `__init__` or how to do it if you must. It's quite a natural thing to want to do, and it breaks in places that are a little unexpected if you do it incorrectly. If I get time in the next few days, I'll do it myself and send in a PR. 


Same with me. I overrode __init__() and it used to work, but I believe I upgraded to a newer version of peewee and it now spits out the following error:

TypeError: __init__() got an unexpected keyword argument 'database_column_name'

@coleifer so what is the right way to init the data fields of peewee.Model descendant class?

> so what is the right way to init the data fields of peewee.Model descendant class

A `Model` class represents a row of data, which it is initialized with. What you mean by "data fields" is unclear to me. You can always override the init method, but with the caveat that it your implementation must accept arbitrary keyword arguments and also call the parent constructor.

thanks @coleifer!

suppose I have a _Car_ class that inherits from _peewee.Model_.  If I want to initialise an object of the _Car_ class with individual values, I can just use the constructor:

```
car_object = Car(seats=6, cylinders=2)
```

So far, so good! 

But now suppose I want to initialise the _Car_ object, starting from another object, say some _CarConfig_ object and the initialisation requires some logic, more than just assigning fields 1-to-1.

Without peewee, I would simply define my \_\_init\_\_() method and put all the initialisation logic there

```
class Car:

     def __init__(self, car_config_object):
           ... some complex initialisation logic here that uses the car_config_object ...
```

but I can't define the \_\_init\_\_() method in _peewee.Model_ descendant classes anymore.  
So where do I put all that complex initialisation logic?


You can still put it in `__init__()` with the caveat that `__init__()` is going to be called not just when instantiating objects yourself, but also every time a `Car` instance is read from a database cursor. I think you probably could make a classmethod on your `Car` object and use that as a factory for complex logic?

good idea - I think the factory method is the way to go!

Could someone share an example of how would that factory method look like ?

@mauriciogracia 

```
class Tweet:
    @classmethod
    def new(cls, *args, **kwargs):
        tweet = cls()
        # Do complicated logic
        return tweet
```

This is just a way to avoid overriding `__init__`.

Since `__new__` does not trigger `__init__` in Python, would there be anything wrong with implicitly using `__new__` instead of explicitly using `Tweet.new` ?

I would not advise it unless you're quite familiar with all the differences between `__new__` and `__init__` (which I myself am not quite sure of). If you need a specialized constructor, my advice is to just write an explicit `@classmethod` **or** you can just make very cautious modifications to `__init__`, e.g.

```python
class User(Model):
    username = TextField()
    def __init__(self, *args, **kwargs):
        super(User, self).__init__(*args, **kwargs)  # Ensure parent init is called correctly.
        # do complicated stuff here.
```

But my advice is to probably stick to a classmethod constructor if your logic is particularly complex.