Serialization with SQLAlchemy and Flask

·

4 min read

If you google what serialization means, it's:

the process of converting data into a format suitable for transmission and storage

Before we dive deeper into what serializing your data is, here is a general explanation of what flask and sqlalchemy is since we will be using them for our serialization purposes. Flask is a framework that provides out of the box configuration to get up and running without having to do too much setup. It allows you to create routes to retrieve requested data from a server. SQLAlchemy is an ORM (Object Relational Mapper) tool used to communicate with your database and maps your instances to a table.

SERIALIZATION

Think of serialization like the way puzzles are made and sold. When a puzzle is created, it's originally one big picture. In order to deliver the puzzle to you, the manufacturer can't send you the entire picture as one piece. Instead, the manufacturer breaks down the picture into smaller pieces, then delivers the box to you. When you receive the box, you can open it and then assemble the pieces back to its original form using the picture on the box as a guide

Similarly, serialization in programming takes complex information (like a whole database or an object) and breaks it down into a simpler, more transportable format (like the puzzle pieces). This makes it easier to save onto a hard drive, send over the internet, or pass data between programs and computers. When needed, this data can be 'assembled' back into its original, complex form, just like putting puzzle pieces together to form the picture on the box.

There are many libraries and resources to use when it comes to serializing your data but today I will be focusing on just two of them: SerializerMixin and Marshmallow. I'll share some example of how you can use them and explain some important considerations when deciding which one would work best for your project.

Let's build a one-to-many relationship where one user can have many services.

class User(db.Model):
    __tablename__ = 'authors'

    serialize_rules = ('-services.user',)

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)

    #relationships
    services = db.relationship('Service', back_populates='user', cascade='all, delete-orphan')

class Service(db.Model):
    __tablename__ = 'books'

    serialize_rules = ('-services.user',)

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String, nullable=False)

    #relationship
    user = db.relationship('User', back_populates='services')

SerializerMixin

Now that we have our models, if you haven't already, install sqlalchemy_serializer:

pip install SQLAlchemy-serializer

Then import SerializerMixin:

from sqlalchemy_serializer import SerializerMixin

In your models, pass SerializerMixin:

class Model(SerializerMixin):
    pass

Your code should look something like this:

from sqlalchemy_serializer import SerializerMixin

class User(db.Model, SerializerMixin):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)

    #relationships
    services = db.relationship('Service', back_populates='user', cascade='all, delete-orphan')

class Service(db.Model, SerializerMixin):
    __tablename__ = 'services'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String, nullable=False)

    #relationship
    user = db.relationship('User', back_populates='services')

Now we can start formatting our data using the serialize rules in our models.

from sqlalchemy_serializer import SerializerMixin

class User(db.Model, SerializerMixin):
    __tablename__ = 'authors'

    serialize_rules = ('-services.user',)

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)

    #relationships
    services = db.relationship('Service', back_populates='user', cascade='all, delete-orphan')

class Service(db.Model, SerializerMixin):
    __tablename__ = 'books'

    serialize_rules = ('-user.services',)

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String, nullable=False)

    #relationship
    user = db.relationship('User', back_populates='services')

SerializerMixin focuses on simplifying serialization within SQLAlchemy models, while Marshmallow offers a broader range of serialization and validation features for various data structures.

Marshmallow

Install Marshmallow:

pip install flask-marshmallow

Here is a link to configure marshmallow in your project before continuing.

In Marshmallow, you serialize your data in the routes. Whereas with SerializerMixin, you serialize your data in the models.

In the Routes:

#Marshmallow Schema's for Users and Services
class UserSchema(ma.Schema):
  class Meta:
    model = User
    load_instance = True

  id = ma.Integer()
  name = ma.String()


class ServiceSchema(ma.Schema):
  class Meta:
    model = Service
    load_instance = True

  title = ma.String()
  #if you want a nested object from a model.Nested method
  #this will include the user who owns the service
  user = fields.Nested(UserSchema)
  id = ma.Number()

  url = ma.Hyperlinks(
    {
        "collection": ma.URLFor("services")
    }
)

services_schema = ServiceSchema(many=True)

class Services(Resource):

  def get(self):
    services = Service.query.all()
    #services_schema.dump is like .to_dict() from SerializeMixin
    results = services_schema.dump(services)
    return results, 200

api.add_resource(Services, '/services', endpoint='services')

Marshmallow is designed for complex data serialization and deserialization in various formats. As you can see in the code above, you have more flexibility and control over what attributes you want included in the object returned when the route is hit. services_schema = ServiceSchema(many=True) lets marshmallow know that a collection of objects need to be serialized instead of just one. Remove many=True when your serializing a single object. Marshmallow makes it easier to manage complex data structures and it's used for applications that require detailed control over serializing your data.

SerializerMixin is for simpler applications that don't need to much control over serializing data. Customization and validation is limited and there's not much flexibility.

With marshmallow you have more control over formatting your data and you can decide what you want to return. SerializerMixin works best for simple applications with a minimal setup. Using Marshmallow and SerializeMixin depends on your project's needs, the complexity of your data serialization, and how much control you need over the serialization process.