0

I've overridden create_view() method inside my mongoengine.ModelView:

from mongoengine.errors import NotUniqueError
from pymongo.errors import DuplicateKeyError


class MyView(mongoengine.ModelView):
@expose('/create/', methods=('GET', 'POST'))
    def create_view(self):
        try:
            return super(MyView, self).create_view()
        except (NotUniqueError, DuplicateKeyError):
            flash('Duplicated search word! Redirected to existing record.', 'error')

            # redirect logic here
            location = "/"
            return redirect(location)

I am able to catch that NotUniqueError exception while running server with app.run(debug=True).

But if debug=False that try:except block is ignored:

Traceback (most recent call last):
  File "/home/pata/venvs/lib/python3.6/site-packages/mongoengine/document.py", line 389, in save
    object_id = self._save_create(doc, force_insert, write_concern)
  File "/home/pata/venvs/lib/python3.6/site-packages/mongoengine/document.py", line 452, in _save_create
    object_id = wc_collection.insert_one(doc).inserted_id
  File "/home/pata/venvs/lib/python3.6/site-packages/pymongo/collection.py", line 693, in insert_one
    session=session),
  File "/home/pata/venvs/lib/python3.6/site-packages/pymongo/collection.py", line 607, in _insert
    bypass_doc_val, session)
  File "/home/pata/venvs/lib/python3.6/site-packages/pymongo/collection.py", line 595, in _insert_one
    acknowledged, _insert_command, session)
  File "/home/pata/venvs/lib/python3.6/site-packages/pymongo/mongo_client.py", line 1248, in _retryable_write
    return self._retry_with_session(retryable, func, s, None)
  File "/home/pata/venvs/lib/python3.6/site-packages/pymongo/mongo_client.py", line 1201, in _retry_with_session
    return func(session, sock_info, retryable)
  File "/home/pata/venvs/lib/python3.6/site-packages/pymongo/collection.py", line 592, in _insert_command
    _check_write_command_response(result)
  File "/home/pata/venvs/lib/python3.6/site-packages/pymongo/helpers.py", line 217, in _check_write_command_response
    _raise_last_write_error(write_errors)
  File "/home/pata/venvs/lib/python3.6/site-packages/pymongo/helpers.py", line 198, in _raise_last_write_error
    raise DuplicateKeyError(error.get("errmsg"), 11000, error)
pymongo.errors.DuplicateKeyError: E11000 duplicate key error collection: test_db.search_word index: word_1 dup key: { : "word" }

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pata/venvs/lib/python3.6/site-packages/flask_admin/contrib/mongoengine/view.py", line 566, in create_model
    model.save()
  File "/home/pata/venvs/lib/python3.6/site-packages/mongoengine/document.py", line 412, in save
    raise NotUniqueError(message % six.text_type(err))
mongoengine.errors.NotUniqueError: Tried to save duplicate unique keys (E11000 duplicate key error collection: test_db.search_word index: word_1 dup key: { : "word" })

PATAPOsha
  • 372
  • 3
  • 18

1 Answers1

1

The exception isn't occurring in method create_view but in method create_model. It tells you this in the stack trace:

Traceback (most recent call last):
  File "/home/pata/venvs/lib/python3.6/site-packages/flask_admin/contrib/mongoengine/view.py", line 566, in create_model
    model.save()

Also note the different way Flask-Admin handles mongoengine exceptions in debug and production environments.

What you need to do is override create_model and handle your specific exception cases there, e.g.

class MyView(mongoengine.ModelView):

    def create_model(self, form):
        """
            Create model helper
            :param form:
                Form instance
        """
        try:
            model = self.model()
            form.populate_obj(model)
            self._on_model_change(form, model, True)
            model.save()
        except (NotUniqueError, DuplicateKeyError):

            # Your code here

        except Exception as ex:
            if not self.handle_view_exception(ex):
                flash(gettext('Failed to create record. %(error)s',
                              error=format_error(ex)),
                      'error')
                log.exception('Failed to create record.')

            return False
        else:
            self.after_model_change(form, model, True)

        return model
pjcunningham
  • 7,676
  • 1
  • 36
  • 49
  • yep, that worked, thx. But from `create_model()` it is imposible to `return redirect(url)`. – PATAPOsha Jul 29 '19 at 11:52
  • I have to use both `create_view(self)` and `create_model(self, form)`, manually raising `NotUniqueError` inside `create_model` and catching it inside `create_view`. That seems so ugly) – PATAPOsha Jul 29 '19 at 11:54