serializers

A minimal port of rails' ActiveModel Serializer


Keywords
serializer, serializing, serialization, json, active, model
License
MIT
Install
pip install serializers==0.2.4

Documentation

Serializers

Build Status

This is an attempt at a simple Python port of ActiveModel::Serializers. It's a bit minimal at the moment, but any contributions are welcome.

Installation

All you have to do is run:

$ pip install serializers

Usage

If you have an object that you want to render as JSON and don't necessarily want to render all of it, or want to modify the shape of the object. You could certainly do all of that specification in the object, but that is not great separation of concerns and can get tedious.

Single Object Serialization

Usually you would define one or more serializer per object class:

  class MyObjectSerialzer( Serializer ):
    pass

  # NOTE: feel free to reach out if you have a way to move this into the class definition

  MyObjectSerializer.attribute( 'attribute_name' )
  MyObjectSerializer.attribute( 'internal_name', key = 'public_name' )
  MyObjectSerializer.attributes( 'list', 'of', 'attributes' )

and then in your rendering, you would init a new serializer with the object you want serialized:

  obj = MyObject( ) # whatever this is
  json = MyObjectSerializer( obj ).to_json()

  return json # or whatever your rendering logic is

You can also render the object to a dictionary, if you want

  serializer = MyObjectSerialzier( obj )
  obj_dict   = serializer.to_dict()

ComplexObjectSerialization

If you have an object that has subobjects you want custom serialized, you can define serializer relationships.

  ChildSerializer( Serializer ):
    pass
  
  ChildSerializer.attriutes( 'name', 'ordinal')


  ParentSerializer( Serializer ):
    pass

  ParentSerializer.attribute( 'name' ) \
                  .has_many( 'children', serializer = ChildSerializer )


  parent = Parent( 'Bob' )
  parent.children = [ Child( 'Jim', 'first' ), Child( 'Jamie', 'second' ) ]

  ParentSerializer( parent ).to_json()  # =>  { "name": "Bob",
                                        #       "children": [
                                        #         { "name": "Jim",
                                        #           "ordinal": "first"
                                        #         },
                                        #         { "name": "Jamie",
                                        #           "ordinal": "second"
                                        #         },
                                        #       ]
                                        #     }

Optional Parameter Passing & Serializer Methods

Because the serializer object is now the external interface definition for your object separate from it, it makes sense you would be able to define custom serialization methods for your objects. And you can.

  class PersonSerializer(Serializer):

    @classmethod
    def formatted_name( cls, item, args ):
      return f"{item.title} {item.first_name} {item.last_name} {item.suffix}"

    # in case you were wondering about the args in that method, that's so that you can pass in additional data into the serializer
    @classmethod
    def timezones_from_you( cls, item, args ):
      zone = timezone( args.get('timezone', "UTC") )
      # let's pretend this is a thing you can do
      return item.timezone - zone

  PersonSerializer.attributes(  'formatted_name ',
                                'timezones_from_you' )

With this, you can, in your controller, do

  def show( self, args ):
    person = Person.find( args[ 'person_id' ] )
    return PersonSerializer( person, args ).to_json()

which should render something along the lines of

{ "formatted_name" : "Mr. Bob Dobalina Sr. III",
  "timezones_from_you": -3 }

Example

  class Model():

    def __init__( self ):
      self.public_data = "stuff here"
      self.secret      = "magic secrets no one should ever see"
      self.rename_me   = "i have been renamed!"

    def func( self ):
      return "reslt of a function"

    # if you are using SQL Alchemy
    children = relationship("Child")
  

  class ModelSerializer(Serializer):
    pass

  ModelSerializer.attributes( 'public_data', 'func' )                 \
                 .attribute( 'rename_me', key='reanamed_var' )        \
                 .has_many( 'children', serializer = ChildSerializer )

  ModelSerializer( Model() ).to_json() # => '{  "func" : "reslt of a function"
                                       #        "public_data": "stuff here",
                                       #        "reanamed_var": "i have been renamed!"
                                       #        "children": [
                                       #          { "name": "Jim",
                                       #            "ordinal": "first"
                                       #          },
                                       #          { "name": "Jamie",
                                       #            "ordinal": "second"
                                       #         },
                                       #       ]
                                       #     }'

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/gaorlov/serializer.

License

The gem is available as open source under the terms of the MIT License.