Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added __init__.py
Empty file.
188 changes: 188 additions & 0 deletions model_serializer/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
================
Model Serializer
================

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Frest--framework-lightgray.png?logo=github
:target: https://github.com/OCA/rest-framework/tree/13.0/model_serializer
:alt: OCA/rest-framework
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/rest-framework-13-0/rest-framework-13-0-model_serializer
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/271/13.0
:alt: Try me on Runbot

|badge1| |badge2| |badge3| |badge4| |badge5|

This module takes advantage of the concepts introduced in the `datamodel` module to offer mechanisms similar to
(a subset of) the `ModelSerializer` in Django REST Framework. That is, use the definition of the Odoo model to
partially automate the definition of a corresponding `Datamodel` class.

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_

**Table of contents**

.. contents::
:local:

Usage
=====

:code:`ModelSerializer` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The :code:`ModelSerializer` class inherits from the :code:`Datamodel` class and adds functionalities. Therefore any
class inheriting from :code:`ModelSerializer` can be used the exact same way as any other :code:`Datamodel`.

Basic usage
***********

Here is a basic example::

from odoo.addons.model_serializer.core import ModelSerializer

class PartnerInfo(ModelSerializer):
_name = "partner.info"
_model = "res.partner"
_model_fields = ["id", "name", "country_id"]

The result is equivalent to the following :code:`Datamodel` classes::

from marshmallow import fields

from odoo.addons.datamodel.core import Datamodel
from odoo.addons.datamodel.fields import NestedModel


class PartnerInfo(Datamodel):
_name = "partner.info"

id = fields.Integer(required=True, allow_none=False, dump_only=True)
name = fields.String(required=True, allow_none=False)
country = NestedModel("_auto_nested_serializer.res.country")


class _AutoNestedSerializerResCountry(Datamodel):
_name = "_auto_nested_serializer.res.country"

id = fields.Integer(required=True, allow_none=False, dump_only=True)
display_name = fields.String(dump_only=True)


Overriding fields definition
****************************

It is possible to override the default definition of fields as such::

from odoo.addons.model_serializer.core import ModelSerializer

class PartnerInfo(ModelSerializer):
_name = "partner.info"
_model = "res.partner"
_model_fields = ["id", "name", "country_id"]

country_id = NestedModel("country.info")

class CountryInfo(ModelSerializer):
_name = "country.info"
_model = "res.country"
_model_fields = ["code", "name"]

In this example, we override a :code:`NestedModel` but it works the same for any other field type.

(De)serialization
*****************

:code:`ModelSerializer` does all the heavy-lifting of transforming a :code:`Datamodel` instance into the corresponding
:code:`recordset`, and vice-versa.

To transform a recordset into a (list of) :code:`ModelSerializer` instance(s) (serialization), do the following::

partner_info = self.env.datamodels["partner.info"].from_recordset(partner)

This will return a single instance; if your recordset contains more than one record, you can get a list of instances
by passing :code:`many=True` to this method.


To transform a :code:`ModelSerializer` instance into a recordset (de-serialization), do the following::

partner = partner_info.to_recordset()

Unless an existing partner can be found (see below), this method **creates a new record** in the database. You can avoid
that by passing :code:`create=False`, in which case the system will only create them in memory (:code:`NewId` recordset).

In order to determine if the corresponding Odoo record already exists or if a new one should be created, the system
checks by default if the :code:`id` field of the instance corresponds to a database record. This default behavior can be
modified like so::

class CountryInfo(ModelSerializer):
_name = "country.info"
_model = "res.country"
_model_fields = ["code", "name"]

def get_odoo_record(self):
if self.code:
return self.env[self._model].search([("code", "=", self.code)])
return super().get_odoo_record()

Changelog
=========

13.0.1.0.0
~~~~~~~~~~

First official version.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/rest-framework/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/rest-framework/issues/new?body=module:%20model_serializer%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Wakari

Contributors
~~~~~~~~~~~~

* François Degrave <f.degrave@wakari.be>

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/rest-framework <https://github.com/OCA/rest-framework/tree/13.0/model_serializer>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
4 changes: 4 additions & 0 deletions model_serializer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import builder
from . import core
from . import field_converter
from . import serializers
15 changes: 15 additions & 0 deletions model_serializer/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2021 Wakari SRL (http://www.wakari.be)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).

{
"name": "Model Serializer",
"summary": "Automatically translate Odoo models into Datamodels "
"for (de)serialization",
"version": "13.0.1.0.0",
"development_status": "Alpha",
"license": "LGPL-3",
"website": "https://github.com/OCA/rest-framework",
"author": "Wakari, Odoo Community Association (OCA)",
"depends": ["datamodel"],
"data": [],
}
23 changes: 23 additions & 0 deletions model_serializer/builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from odoo import models

from odoo.addons.datamodel.core import MetaDatamodel, _datamodel_databases

from .core import ModelSerializer


class DatamodelBuilder(models.AbstractModel):
_inherit = "datamodel.builder"

def load_datamodels(self, module, datamodels_registry=None):
super().load_datamodels(module, datamodels_registry=datamodels_registry)
datamodels_registry = (
datamodels_registry or _datamodel_databases[self.env.cr.dbname]
)
for datamodel_class in MetaDatamodel._modules_datamodels[module]:
self._extend_model_serializer(datamodel_class, datamodels_registry)

def _extend_model_serializer(self, datamodel_class, registry):
"""Extend the datamodel_class with the fields declared in `_model_fields`"""
if issubclass(datamodel_class, ModelSerializer):
new_class = datamodel_class._extend_from_odoo_model(registry, self.env)
new_class._build_datamodel(registry)
Loading