Search code examples
pythonwerkzeug

Python Werkzeug: modify Request values (forms and args) prior to retrieval


Is there a way in Werkzeug to edit the request values (forms and args) before using it?

I need to encode the request values from utf8 to iso88591. I created a function to handle this.

I would like to use this function on all form values so that I avoid the second line of the following:

lcl_var = request.form['post_arg']        
lcl_var = encode_utf8_to_iso88591(lcl_var)

I couldn't figure out what I needed from the Werkzeug docs. I imagine there's a way to subclass the Request class and override a one of its methods that handles the values. Would really appreciate a concrete example on how to implement this well.


Solution

  • A limited example exists on extending request parsing at the Werkzeug docs. It's a little buried, but it's sound.

    http://werkzeug.pocoo.org/docs/request_data/#how-to-extend-parsing

    Since Werkzeug is a pretty low-level tool over HTTP, this functionality could also be implemented in your request dispatcher (assuming a structure similar to the one in the Werkzeug tutorial, the function that applies the url map to the request.)

    EDIT:

    It seems that per the Werkzeug docs, the best way to do this is to process your own request property out of the stream. It'd be nice to do this is a way that preserves the immutability of the request.form property:

    def encode(value):
        #Your logic for the new dict vals
        return 'foo!'
    
    class MixInRequest(Request):
        max_content_length = 1024 * 1024 * 4
    
        @cached_property
        def lcl_data(self):
            if self.method in ['POST','PUT','PATCH']:
                fields = dict([(key, encode(val)) for (key,val) in self.form.items()])
                return ImmutableMultiDict(fields)
            return None
    

    This sets a request property lcl_data (named after your function) that will parse on first access and cache for subsequent calls. It only functions for methods that would populate request.form.

    Full example here:

    https://gist.github.com/DeaconDesperado/7292574