'Save the :class:`~mongoengine.Document` to the database. If the
document already exists, it will be updated, otherwise it will be
created.
:param force_insert: only try to create a new document, don\'t allow
updates of existing documents.
:param validate: validates the document; set to ``False`` to skip.
:param clean: call the document clean method, requires `validate` to be
True.
:param write_concern: Extra keyword arguments are passed down to
:meth:`~pymongo.collection.Collection.save` OR
:meth:`~pymongo.collection.Collection.insert`
which will be used as options for the resultant
``getLastError`` command.  For example,
``save(..., write_concern={w: 2, fsync: True}, ...)`` will
wait until at least two servers have recorded the write and
will force an fsync on the primary server.
:param cascade: Sets the flag for cascading saves.  You can set a
default by setting "cascade" in the document __meta__
:param cascade_kwargs: (optional) kwargs dictionary to be passed throw
to cascading saves.  Implies ``cascade=True``.
:param _refs: A list of processed references used in cascading saves
:param save_condition: only perform save if matching record in db
satisfies condition(s) (e.g. version number).
Raises :class:`OperationError` if the conditions are not satisfied
:param signal_kwargs: (optional) kwargs dictionary to be passed to
the signal calls.
.. versionchanged:: 0.5
In existing documents it only saves changed fields using
set / unset.  Saves are cascaded and any
:class:`~bson.dbref.DBRef` objects that have changes are
saved as well.
.. versionchanged:: 0.6
Added cascading saves
.. versionchanged:: 0.8
Cascade saves are optional and default to False.  If you want
fine grain control then you can turn off using document
meta[\'cascade\'] = True.  Also you can pass different kwargs to
the cascade save using cascade_kwargs which overwrites the
existing kwargs with custom values.
.. versionchanged:: 0.8.5
Optional save_condition that only overwrites existing documents
if the condition is satisfied in the current db record.
.. versionchanged:: 0.10
:class:`OperationError` exception raised if save_condition fails.
.. versionchanged:: 0.10.1
:class: save_condition failure now raises a `SaveConditionError`
.. versionchanged:: 0.10.7
Add signal_kwargs argument'

def save(self, force_insert=False, validate=True, clean=True, write_concern=None, cascade=None, cascade_kwargs=None, _refs=None, save_condition=None, signal_kwargs=None, **kwargs):

    if self._meta.get('abstract'):
        raise InvalidDocumentError('Cannot    save    an    abstract    document.')
    signal_kwargs = (signal_kwargs or {})
    signals.pre_save.send(self.__class__, document=self, **signal_kwargs)
    if validate:
        self.validate(clean=clean)
    if (write_concern is None):
        write_concern = {'w': 1}
    doc = self.to_mongo()
    created = (('_id' not in doc) or self._created or force_insert)
    signals.pre_save_post_validation.send(self.__class__, document=self, created=created, **signal_kwargs)
    if self._meta.get('auto_create_index', True):
        self.ensure_indexes()
    try:
        if created:
            object_id = self._save_create(doc, force_insert, write_concern)
        else:
            (object_id, created) = self._save_update(doc, save_condition, write_concern)
        if (cascade is None):
            cascade = (self._meta.get('cascade', False) or (cascade_kwargs is not None))
        if cascade:
            kwargs = {'force_insert': force_insert, 'validate': validate, 'write_concern': write_concern, 'cascade': cascade}
            if cascade_kwargs:
                kwargs.update(cascade_kwargs)
            kwargs['_refs'] = _refs
            self.cascade_save(**kwargs)
    except pymongo.errors.DuplicateKeyError as err:
        message = u'Tried    to    save    duplicate    unique    keys    (%s)'
        raise NotUniqueError((message % six.text_type(err)))
    except pymongo.errors.OperationFailure as err:
        message = 'Could    not    save    document    (%s)'
        if re.match('^E1100[01]    duplicate    key', six.text_type(err)):
            message = u'Tried    to    save    duplicate    unique    keys    (%s)'
            raise NotUniqueError((message % six.text_type(err)))
        raise OperationError((message % six.text_type(err)))
    id_field = self._meta['id_field']
    if (created or (id_field not in self._meta.get('shard_key', []))):
        self[id_field] = self._fields[id_field].to_python(object_id)
    signals.post_save.send(self.__class__, document=self, created=created, **signal_kwargs)
    self._clear_changed_fields()
    self._created = False
    return self
