Metadata-Version: 2.1
Name: serialchemy
Version: 1.0.2
Summary: Serializers for SQLAlchemy models.
Home-page: https://github.com/ESSS/serialchemy
Author: ESSS
Author-email: foss@esss.co
License: MIT
Keywords: serialchemy
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.8
Provides-Extra: docs
Provides-Extra: testing
License-File: LICENSE

======================================================================
Serialchemy
======================================================================


.. image:: https://img.shields.io/pypi/v/serialchemy.svg
    :target: https://pypi.python.org/pypi/serialchemy

.. image:: https://img.shields.io/pypi/pyversions/serialchemy.svg
    :target: https://pypi.org/project/serialchemy

.. image:: https://github.com/ESSS/serialchemy/workflows/build/badge.svg
    :target: https://github.com/ESSS/serialchemy/actions

.. image:: https://codecov.io/gh/ESSS/serialchemy/branch/master/graph/badge.svg
    :target: https://codecov.io/gh/ESSS/serialchemy

.. image:: https://img.shields.io/readthedocs/serialchemy.svg
    :target: https://serialchemy.readthedocs.io/en/latest/

.. image:: https://sonarcloud.io/api/project_badges/measure?project=ESSS_serialchemy&metric=alert_status
    :target: https://sonarcloud.io/project/overview?id=ESSS_serialchemy


SQLAlchemy model serialization.
===============================

Motivation
----------

**Serialchemy** was developed as a module of Flask-RESTAlchemy_, a lib to create Restful APIs
using Flask and SQLAlchemy. We first tried marshmallow-sqlalchemy_, probably the most
well-known lib for SQLAlchemy model serialization, but we faced `issues related to nested
models <https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues/67>`_. We also think
that is possible to build a simpler and more maintainable solution by having SQLAlchemy_ in
mind from the ground up, as opposed to marshmallow-sqlalchemy_ that had to be
designed and built on top of marshmallow_.

.. _SQLAlchemy: www.sqlalchemy.org
.. _marshmallow-sqlalchemy: http://marshmallow-sqlalchemy.readthedocs.io
.. _marshmallow: https://marshmallow.readthedocs.io
.. _Flask-RESTAlchemy: https://github.com/ESSS/flask-restalchemy

How to Use it
-------------

Serializing Generic Types
.........................

Suppose we have an `Employee` SQLAlchemy_ model declared:

.. code-block:: python

    class Employee(Base):
        __tablename__ = "Employee"

        id = Column(Integer, primary_key=True)
        fullname = Column(String)
        admission = Column(DateTime, default=datetime(2000, 1, 1))
        company_id = Column(ForeignKey("Company.id"))
        company = relationship(Company)
        company_name = column_property(
            select([Company.name]).where(Company.id == company_id)
        )
        password = Column(String)

`Generic Types`_ are automatically serialized by `ModelSerializer`:

.. code-block:: python

    from serialchemy import ModelSerializer

    emp = Employee(fullname="Roberto Silva", admission=datetime(2019, 4, 2))

    serializer = ModelSerializer(Employee)
    serializer.dump(emp)

    # >>
    {
        "id": None,
        "fullname": "Roberto Silva",
        "admission": "2019-04-02T00:00:00",
        "company_id": None,
        "company_name": None,
        "password": None,
    }

New items can be deserialized by the same serializer:

.. code-block:: python

    new_employee = {"fullname": "Jobson Gomes", "admission": "2018-02-03"}
    serializer.load(new_employee)

    # >> <Employee object at 0x000001C119DE3940>

Serializers do not commit into the database. You must do this by yourself:

.. code-block:: python

    emp = serializer.load(new_employee)
    session.add(emp)
    session.commit()

.. _`Generic Types`: https://docs.sqlalchemy.org/en/rel_1_2/core/type_basics.html#generic-types

Custom Serializers
..................

For anything beyond `Generic Types`_ we must extend the `ModelSerializer` class:

.. code-block:: python

    class EmployeeSerializer(ModelSerializer):

        password = Field(load_only=True)  # passwords should be only deserialized
        company = NestedModelField(Company)  # dump company as nested object


    serializer = EmployeeSerializer(Employee)
    serializer.dump(emp)
    # >>
    {
        "id": 1,
        "fullname": "Roberto Silva",
        "admission": "2019-04-02T00:00:00",
        "company": {"id": 3, "name": "Acme Co"},
    }


Extend Polymorphic Serializer
+++++++++++++++++++++++++++++
One of the possibilities is to serialize SQLalchemy joined table inheritance and
it child tables as well. To do such it's necessary to set a variable with
the desired model class name. Take this `Employee` class with for instance and let us
assume it have a joined table inheritance:

.. code-block:: python

    class Employee(Base):
        ...
        type = Column(String(50))

        __mapper_args__ = {"polymorphic_identity": "employee", "polymorphic_on": type}


    class Engineer(Employee):
        __tablename__ = "Engineer"
        id = Column(Integer, ForeignKey("employee.id"), primary_key=True)
        association = relationship(Association)

        __mapper_args__ = {
            "polymorphic_identity": "engineer",
        }

To use a extended `ModelSerializer` class on the `Engineer` class, you should create
the serializer as it follows:

.. code-block:: python

    class EmployeeSerializer(
        PolymorphicModelSerializer
    ):  # Since this class will be polymorphic

        password = Field(load_only=True)
        company = NestedModelField(Company)


    class EngineerSerializer(EmployeeSerializer):
        __model_class__ = Engineer  # This is the table Serialchemy will refer to
        association = NestedModelField(Association)

Contributing
------------

For guidance on setting up a development environment and how to make a
contribution to serialchemy, see the `contributing guidelines`_.

.. _contributing guidelines: https://github.com/ESSS/serialchemy/blob/master/CONTRIBUTING.rst


Release
-------
A reminder for the maintainers on how to make a new release.

Note that the VERSION should folow the semantic versioning as X.Y.Z Ex.: v1.0.5

Create a release-VERSION branch from upstream/master.
Update CHANGELOG.rst.
Push a branch with the changes.
Once all builds pass, push a VERSION tag to upstream. Ex: git tag v1.0.5; git push origin --tags
Merge the PR.


History
=======
1.0.2 (2025-07-08)
------------------
* Adjust PolymorphicModelSerializer to accept a pure Enum as polymorphic identity

1.0.1 (2023-17-11)
------------------
* Fix license placement on setup.py

1.0.0 (2023-14-11)
------------------
* Add support for SQLAlchemy imperative (classical) mapping
* Drop support for Python versions bellow 3.8
* Drop support for SQLAlchemy 1.3

0.4.0 (2023-12-11)
------------------
* Fix to get model attribute name instead of table column name on polymorphic serializer
* Extends the PolymorphicModelSerializer to accept also column descriptors when searching
  for the polymorphic column key.
* Add support for serialization of Python Enums
* Change PolymorphicModelSerializer to support inherited models of inherited models
* Change Field to use a default serializer for not None values
* Added support for sqlalchemy 1.4
* Add EnumKeySerializer

0.3.0 (2019-17-07)
------------------
* Add the composite fields to list of properties of model, to serialize that fields if it type is in EXTRA_SERIALIZERS.
* Fix error for SQLAlchemy composite attributes
* Added free functions dump and load so users can quickly dump a SQLAlchemy model without having to instancialize
  ModelSerializer.

0.2.0 (2019-03-22)
------------------

* Fix: Error when deserializing of nested models when SQLAlchemy model primary
  key attribute name differs from the column name
* Allow EXTRA_SERIALIZERS to be defined in runtime
* Check if a session was given when serializing/deserializing nested fields

0.1.0 (2019-02-12)
------------------

* First release on PyPI.
