Catching DuplicateKeyError when using Ming

10 views
Skip to first unread message

Giovanni Colucci

unread,
Jan 23, 2017, 8:32:18 AM1/23/17
to TurboGears
Hello guys,

I am using TG 2.3.10 with Ming I started the project using the quickstart command.

My TG application is basically a REST web service. I am not really sure how to handle DuplicationKeyError when adding new items into my DB.

I thought that catching the DuplicationKeyError from inside my controller method code was enough, but whenever I try to perform a POST request with some duplicate data the application crash and return me a 500 HTTP status code.

The following is a sample code that fail for me, the sensorID field got a UniqueIndex into the model definition.

    @expose('json')
   
@decode_params('json')
   
@validate({
       
"sensorID": validators.String(not_empty=True),
       
"definition": validators.String(not_empty=True)
   
})
   
@require(in_group('admins'))
   
def post(self, *args, **kw):
       
#Check if there was error during the validation process
       
if request.validation['errors']:
            errors
= dict([(field, str(e)) for field, e in request.validation['errors'].items()])
            logger
.warning('Unable to add a sensor type due to a validation error. ' + str(errors))
            response
.status = 400
           
return dict(errors=errors)

       
try:
            sensor
= model.Sensor(
                sensorID
=kw['sensorID'], definition=kw['definition']
           
)
           
#Flush it into the DB
            model
.DBSession.flush()
            response
.status = 201
       
except DuplicateKeyError:
            response
.status = 400
           
return dict(errors="Sensor already present!")
       
except:
            logger
.exception('The sensor type %s was not added due to an unexpected error.' % kw['sensorTypeID'])
            abort
(500)
       
else:
           
return

This is the trackback that I see when I try to insert a document that contain the same sensorID string.

Traceback (most recent call last):
  File "/var/www/backend/envBK/lib/python2.7/site-packages/tg/wsgiapp.py", line 120, in __call__
    response = self.wrapped_dispatch(controller, environ, context)
  File "/var/www/backend/envBK/lib/python2.7/site-packages/tg/appwrappers/mingflush.py", line 58, in __call__
    session.flush_all()
  File "build/bdist.linux-x86_64/egg/ming/odm/odmsession.py", line 411, in flush_all
    sess.flush()
  File "build/bdist.linux-x86_64/egg/ming/odm/base.py", line 27, in inner
    result = func(obj, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/ming/odm/odmsession.py", line 99, in flush
    self.uow.flush()
  File "build/bdist.linux-x86_64/egg/ming/odm/unit_of_work.py", line 45, in flush
    inow(obj, st)
  File "build/bdist.linux-x86_64/egg/ming/odm/base.py", line 27, in inner
    result = func(obj, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/ming/odm/odmsession.py", line 111, in insert_now
    mapper(obj).insert(obj, st, self, **kwargs)
  File "build/bdist.linux-x86_64/egg/ming/odm/base.py", line 27, in inner
    result = func(obj, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/ming/odm/mapper.py", line 71, in insert
    session.impl.insert(doc, validate=False)
  File "build/bdist.linux-x86_64/egg/ming/session.py", line 23, in wrapper
    return func(self, doc, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/ming/session.py", line 163, in insert
    bson = self._impl(doc).insert(data, safe=kwargs.get('safe', True))
  File "build/bdist.linux-x86_64/egg/pymongo/collection.py", line 541, in insert
    _check_write_command_response(results)
  File "build/bdist.linux-x86_64/egg/pymongo/helpers.py", line 233, in _check_write_command_response
    raise DuplicateKeyError(error.get("errmsg"), 11000, error)

Seems like I am missing something but I am a bit confused. Could anyone help me in this?

Alessandro Molina

unread,
Jan 23, 2017, 8:40:18 AM1/23/17
to TurboGears
On "except DuplicateKeyError:" you need to expunge the object from the session or the autoflusher will still find the object at the end of the request, will see that it's dirty and pending creation (as the previous flush failed) and will try to create it again.


Most common pattern is just to call ODMSession.clear(), so that all objects are expunged as usually in a well defined api there is nothing you must create/edit if it failed.

--
You received this message because you are subscribed to the Google Groups "TurboGears" group.
To unsubscribe from this group and stop receiving emails from it, send an email to turbogears+unsubscribe@googlegroups.com.
To post to this group, send email to turbo...@googlegroups.com.
Visit this group at https://groups.google.com/group/turbogears.
For more options, visit https://groups.google.com/d/optout.

Giovanni Colucci

unread,
Jan 23, 2017, 8:52:18 AM1/23/17
to TurboGears
Got it! It was really simple.

Thank you very much for the help!!
To unsubscribe from this group and stop receiving emails from it, send an email to turbogears+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages