Repository: MongoEngine/mongoengine

Issue:
Inconsistent Document.__init__ call signatures
It appears that the Document subclassing system leads to some unfortunate inconsistencies.  E.g.:

```
class MyBase(mongoengine.Document):
    name = mongoengine.StringField()
    meta = {'allow_inheritance': True}

class MySub(MyBase):
    pass
```

Given the above, a call like `MyBase('ross')` successfully creates a `MyBase` document with the `name` field set to `'ross'`.  However, an analogous call like `MySub('ross')` raises a `bson.errors.InvalidId` exception, because `MySub` expects an `ObjectId` as `arg[0]` and expects the `name` field at `arg[1]`.  I.e., the calls need to be:

```
base = MyBase('ross')
sub = MySub(bson.ObjectId(), 'ross')
```

This seems, at the very least, to be counter-intuitive.  It also makes overriding `__init__`s tricky because one has to inspect 'private' variables (e.g., `Document._auto_id_field`) to determine how `__init__`s will handle `*args`.

It seems that this disparity between a "top level" Document subclass and an "inherited" Document subclass is based on https://github.com/MongoEngine/mongoengine/blob/d92ed04538e7dcf0e94f87e9c3272c0f8a3c1ee0/mongoengine/base/metaclasses.py#L362:

```
        new_class._auto_id_field = False
        if not new_class._meta.get('id_field'):
            new_class._auto_id_field = True
            new_class._meta['id_field'] = 'id'
            new_class._fields['id'] = ObjectIdField(db_field='_id')
            new_class._fields['id'].name = 'id'
            new_class.id = new_class._fields['id']
```

 and https://github.com/MongoEngine/mongoengine/blob/d92ed04538e7dcf0e94f87e9c3272c0f8a3c1ee0/mongoengine/base/document.py#L46:

```
            if self._auto_id_field:
                next(field)
```

A "top level" document without an explicitly set `_meta["id_field"]` will have `_auto_id_field` set to `True` and thus its `__init__` will skip over the `id` fields in `_fields_ordered`, while a subclass will inherit the parent's automatically generated `_meta["id_field"]` and thus the subclass's `_auto_id_field` will remain `False`, and the subclass's `__init__` will not skip over the `id` field in `_fields_ordered`.

I'm not aware of any advantage gained by handling `__init__`s in this bifurcated way, and it appears that this could be reconciled by subclasses inheriting their parent's value for `_auto_id_field`, something like:

```
new_class._auto_id_field = False if parent_doc_class is None else parent_doc_class._auto_id_field
```



Discussion:

Resolving patch:
diff --git a/mongoengine/base/metaclasses.py b/mongoengine/base/metaclasses.py
--- a/mongoengine/base/metaclasses.py
+++ b/mongoengine/base/metaclasses.py
@@ -359,7 +359,8 @@ def __new__(cls, name, bases, attrs):
                     new_class.id = field
 
         # Set primary key if not defined by the document
-        new_class._auto_id_field = False
+        new_class._auto_id_field = getattr(parent_doc_cls,
+                                           '_auto_id_field', False)
         if not new_class._meta.get('id_field'):
             new_class._auto_id_field = True
             new_class._meta['id_field'] = 'id'


Test patch: