@@ -138,7 +138,7 @@ from datetime import datetime
138138from openstack_odooclient import RecordBase
139139
140140class CustomRecord (RecordBase[" CustomRecordManager" ]):
141- custom_field: date
141+ custom_field: datetime
142142 """ Description of the field."""
143143```
144144
@@ -791,6 +791,230 @@ The following internal attributes are also available for use in methods:
791791* ` _odoo ` (` odoorpc.ODOO ` ) - The OdooRPC connection object
792792* ` _env ` (` odoorpc.env.Environment ` ) - The OdooRPC environment object for the model
793793
794+ ## Mixins
795+
796+ Python supports [ multiple inheritance] ( https://docs.python.org/3/tutorial/classes.html#multiple-inheritance )
797+ when creating new classes. A common use case for multiple inheritance is to extend
798+ functionality of a class through the use of * mixin classes* , which are minimal
799+ classes that only consist of supplementary attributes and methods, that get added
800+ to other classes through subclassing.
801+
802+ The OpenStack Odoo Client library for Python supports the use of mixin classes
803+ to add functionality to custom record and manager classes in a modular way.
804+ Multiple mixins can be added to record and manager classes to allow mixing and
805+ matching additional functionality as required.
806+
807+ ### Using Mixins
808+
809+ To extend the functionality of your custom record and manager classes,
810+ append the mixins for the record class and/or record manager class
811+ ** AFTER** the inheritance for ` RecordBase ` and ` RecordManagerBase ` .
812+ You also need to specify the ** same** type arguments to the mixins as
813+ is already being done for ` RecordBase ` and ` RecordManagerBase ` .
814+
815+ ``` python
816+ from __future__ import annotations
817+
818+ from openstack_odooclient import (
819+ NamedRecordManagerMixin,
820+ NamedRecordMixin,
821+ RecordBase,
822+ RecordManagerBase,
823+ )
824+
825+ class CustomRecord (
826+ RecordBase[" CustomRecordManager" ],
827+ NamedRecordMixin[" CustomRecordManager" ],
828+ ):
829+ custom_field: str
830+ """ Description of the field."""
831+
832+ class CustomRecordManager (
833+ RecordManagerBase[CustomRecord],
834+ NamedRecordManagerMixin[CustomRecord],
835+ ):
836+ env_name = " custom.record"
837+ record_class = CustomRecord
838+ ```
839+
840+ That's all that needs to be done. The additional attributes and/or methods
841+ should now be available on your record and manager objects.
842+
843+ The following mixins are provided with the Odoo Client library.
844+
845+ #### Named Records
846+
847+ If your record model has a unique ` name ` field on it (of ` str ` type),
848+ you can use the ` NamedRecordMixin ` and ` NamedRecordManagerMixin ` mixins
849+ to define the ` name ` field on the record class, and add the
850+ ` get_by_name ` method to your custom record manager class.
851+
852+ ``` python
853+ from __future__ import annotations
854+
855+ from openstack_odooclient import (
856+ NamedRecordManagerMixin,
857+ NamedRecordMixin,
858+ RecordBase,
859+ RecordManagerBase,
860+ )
861+
862+ class CustomRecord (
863+ RecordBase[" CustomRecordManager" ],
864+ NamedRecordMixin[" CustomRecordManager" ],
865+ ):
866+ custom_field: str
867+ """ Description of the field."""
868+
869+ # Added by NamedRecordMixin:
870+ #
871+ # name: str
872+ # """The unique name of the record."""
873+
874+ class CustomRecordManager (
875+ RecordManagerBase[CustomRecord],
876+ NamedRecordManagerMixin[CustomRecord],
877+ ):
878+ env_name = " custom.record"
879+ record_class = CustomRecord
880+
881+ # Added by NamedRecordManagerMixin:
882+ #
883+ # def get_by_name(...):
884+ # ...
885+ ```
886+
887+ For more information on using record managers with unique ` name ` fields,
888+ see [ Named Record Managers] ( index.md#named-record-managers ) .
889+
890+ #### Coded Records
891+
892+ If your record model has a unique ` code ` field on it (of ` str ` type),
893+ you can use the ` CodedRecordMixin ` and ` CodedRecordManagerMixin ` mixins
894+ to define the ` code ` field on the record class, and add the
895+ ` get_by_code ` method to your custom record manager class.
896+
897+ ``` python
898+ from __future__ import annotations
899+
900+ from openstack_odooclient import (
901+ CodedRecordManagerMixin,
902+ CodedRecordMixin,
903+ RecordBase,
904+ RecordManagerBase,
905+ )
906+
907+ class CustomRecord (
908+ RecordBase[" CustomRecordManager" ],
909+ CodedRecordMixin[" CustomRecordManager" ],
910+ ):
911+ custom_field: str
912+ """ Description of the field."""
913+
914+ # Added by CodedRecordMixin:
915+ #
916+ # code: str
917+ # """The unique name for this record."""
918+
919+ class CustomRecordManager (
920+ RecordManagerBase[CustomRecord],
921+ CodedRecordManagerMixin[CustomRecord],
922+ ):
923+ env_name = " custom.record"
924+ record_class = CustomRecord
925+
926+ # Added by CodedRecordManagerMixin:
927+ #
928+ # def get_by_code(...):
929+ # ...
930+ ```
931+
932+ For more information on using record managers with unique ` code ` fields,
933+ see [ Coded Record Managers] ( index.md#coded-record-managers ) .
934+
935+ ### Creating Mixins
936+
937+ It is possible to create your own custom mixins to incorporate into
938+ custom record and manager classes.
939+
940+ There are two mixin types: ** record mixins** and ** record manager mixins** .
941+
942+ #### Record Mixins
943+
944+ Record mixins are used to add custom fields and methods to record classes.
945+
946+ Here is the full implementation of ` NamedRecordMixin ` as an example
947+ of a mixin for a record class, that simply adds the ` name ` field:
948+
949+ ``` python
950+ from __future__ import annotations
951+
952+ from typing import Generic
953+
954+ from openstack_odooclient import RM , RecordProtocol
955+
956+ class NamedRecordMixin (RecordProtocol[RM ], Generic[RM ]):
957+ name: str
958+ """ The unique name of the record."""
959+ ```
960+
961+ A record mixin consists of a class that subclasses ` RecordProtocol[RM] `
962+ (where ` RM ` is the type variable for a record manager class) to get the type
963+ hints for a record class' common fields and methods. ` Generic[RM] ` is also
964+ subclassed to make the mixin itself a generic class, to allow ` RM ` to be
965+ passed when creating a record class with the mixin.
966+
967+ Once you have the class, simply define any fields and methods you'd like
968+ to add.
969+
970+ You can then use the mixin as shown in [ Using Mixins] ( #using-mixins ) .
971+
972+ When defining custom methods, in addition to accessing fields/methods
973+ defined within the mixin, fields/methods from the ` RecordBase ` class
974+ are also available:
975+
976+ ``` python
977+ from __future__ import annotations
978+
979+ from typing import Generic
980+
981+ from openstack_odooclient import RM , RecordProtocol
982+
983+ class NamedRecordMixin (RecordProtocol[RM ], Generic[RM ]):
984+ name: str
985+ """ The unique name of the record."""
986+
987+ def custom_method (self ) -> None :
988+ self .name # str
989+ self ._env.custom_method(self .id)
990+ ```
991+
992+ #### Record Manager Mixins
993+
994+ Record manager mixins are expected to be mainly used to add custom methods
995+ to a record manager class.
996+
997+ ``` python
998+ from __future__ import annotations
999+
1000+ from typing import Generic
1001+
1002+ from openstack_odooclient import R, RecordManagerProtocol
1003+
1004+ class NamedRecordManagerMixin (RecordManagerProtocol[R], Generic[R]):
1005+ def custom_method (self , record : int | R) -> None :
1006+ self ._env.custom_method( # self._env available from RecordManagerBase
1007+ record if isinstance (record, int ) else record.id,
1008+ )
1009+ ```
1010+
1011+ A record manager mixin consists of a class that subclasses
1012+ ` RecordManagerProtocol[R] ` (where ` R ` is the type variable for a record class)
1013+ to get the type hints for a record manager class' common attributes and
1014+ methods. ` Generic[R] ` is also subclassed to make the mixin itself a generic
1015+ class, to allow ` R ` to be passed when creating a record manager class
1016+ with the mixin.
1017+
7941018## Extending Existing Record Types
7951019
7961020The Odoo Client library provides * limited* support for extending the built-in record types.
0 commit comments