Module xmodel_rest.api
Expand source code
from xinject import XContext
from .client import RestClient
from .errors import XynRestError
from .settings import RestSettings
from xmodel.remote import RemoteApi, RemoteModel
from typing import TypeVar, List, Tuple, Iterable, Union, Type, get_type_hints, TYPE_CHECKING
from logging import getLogger
from xurls.url import URLStr
from xmodel import Field
from abc import ABC
from .structure import RestStructure
from .auth import RestAuth
from xsentinels import Default
from xurls.url import HTTPGet, HTTPPatch, HTTPDelete, URL
from .auth import RestAuth
from .auth import RestAuth
from typing import TypeVar
from .model import RestModel
# It's really bound to `RestModel`, but I need an easier way to tie into lazy-loading
# BaseModel.__init_subclass__ system, so I can lazy-load my own stuff first before it does.
# Decided it was an exercise for future day. We can live with it for now.
M = TypeVar("M", bound=RemoteModel)
class RestApi(RemoteApi[M]):
""" Base `xynlib.orm.base.api.BaseApi` subclass generally used by Rest API's.
Things specific and common to rest api's should go in this class.
See parent `xynlib.orm.base.api.BaseApi` for things in common among all API's.
"""
# Telling system about the default/base rest types we want to use with `RestApi`.
client: RestClient[M]
structure: RestStructure[Field]
auth: RestAuth
settings: RestSettings
# todo: decide if we should just remove the below, not strictly needed, more of a convenience.
#
# Only used for IDE so it knows what type should be here, not used to know which Model to
# allocate object.
# This is because RestModel will tell/pass this into RestApi via `__init__`,
# it happens when a RestModel/BaseModel is created (in BaseModel.__init__).
model: RestModel[M]
def send(self, url: URLStr = None):
""" REQUIRES associated model object [see self.model].
Convenience method to send this single object to API, it simply calls
`xynlib.orm.base.client.Client.send_objs` with a single object in the list
(via `xynlib.orm.base.api.BaseApi.model`).
If you want to send multiple objects, call `xynlib.orm.base.client.Client.send_objs`.
Example is below, it uses a made-up rest model called 'SomeRestModelSubclass'.
(I did not provide all details it would need to use the made-up/imagained rest-api;
trying to illisrate a basic point here is all.
If you want more details on how to make a real full/valid rest-model subclass
see #INSERT-README-LINK#.)
>>> from xmodel_rest import RestModel
>>> class SomeRestModelSubclass(RestModel, base_url="....etc...."):
... pass # Some attributes from the rest-api go here
>>> obj1 = SomeRestModelSubclass()
>>> obj2 = SomeRestModelSubclass()
>>> RestModel.api.client.send_objs([obj1, obj2])
If you pass in a `url` paramater to the `send_objs` method, the url gets appended to the
final constructed url before the url gets validated.
If the url is validated, it will use that final url [with passed in `url` this appended].
For more information about how URL's are appended to each-other see:
`xurls.url.URLMutable.append_url`.
The response from API will update all the values on this object with the results
of the change [all fields will be updated] and with the latest values from API.
You can check for errors on model object via `xmodel.remote.api.response_state`, ie:
>>> from xynlib.orm import BaseModel
>>> obj: BaseModel
>>> # Check response_state to see if it had an error:
>>> obj.api.response_state.had_error
False
"""
# Redirect to client.send_objs:
self.client.send_objs([self.model], url=url)
# This is a resource-type, see `def auth()` doc-comment below for more details.
# Subclasses can override this type-hint, and `RestApi` will allocate the new
# type instead automatically, on demand.
#
# The type-hints inform this class what type of objects to create when `auth` along
# with other special attributes such as `client` and `structure` are needed/asked-for.
#
# You can override the type by making your own type-hint on a sub-class.
# See xmodel.base.api.BaseApi and xmodel.remote.api.RemoteApi for its various special
# type-hinted attributes for more details, it has more detailed comments/documentation on it.
auth: RestAuth
@property
def _auth(self):
"""
Treated a `xyn_resaource.context.Resource`, a context resource for the purposes of sharing
auth credentials. The type-hint assoicated with `auth: XYZ` will be used to grab
a resource of that type from the current context each time we are asked.
Thus resource is the auth object used by your `xmodel.base.client.BaseClient` subclass,
(such as `xynlib.orm.rest.RestClient`),
to set what type should be used for this, in your BaseClient sub-class, make a type-hint
like below.
Let's say you have an auth class you want to use:
>>> import xmodel.base.auth
>>> import xmodel
>>> class MyCoolAuthClass(xmodel.base.auth.RelationAuth)
... pass
You can set a type-hint for it like so, and it will be automatiaclly used when needed:
>>> class MyApi(xmodel.RemoteApi):
... auth: MyCoolAuthClass
Doing that is enough, `xynlib.orm.rest.RestClient` class will see the type-hint and will
grab one of that type from the XContext and return it.
In the example above, it would be a `MyCoolAuthClass` type.
The type-hint is lazily cached in self for fast lookup in the future.
To see details on what the Auth object should do,
see `xmodel.base.auth.BaseAuth`.
"""
auth_type: Type[RestAuth] = self._auth_type
if not auth_type:
# Will get all type-hints, and ensure they are valid type refrences
# (otherwise will error out)
auth_type = get_type_hints(type(self)).get('auth', RestAuth)
self._auth_type = auth_type
# Auth has tokens we want to try and share, treat it as a resource.
return auth_type.grab()
_settings_type: Type[RestSettings] = None
@property
def _settings(self):
""" The config object that this api uses, can be customized per-model. All you have to
do is this to make it a different type:
>>> import xmodel
>>>
>>> class MySettings(BaseSettings):
... my_custom_var: str = xmodel.ConfigVar(
... "MY_CUSTOM_ENVIRONMENTAL_VAR",
... "default"
... )
>>> class MyApi(xmodel.BaseApi[M]):
... settings: MySettings
>>> class MyModel(xmodel.model.BaseModel['MyModel']):
... api: MyApi
The type-hints are enough to tell the system what types to use. They also will
tell any IDE in use about what type it should be, for type-completion.
So it's sort of doing double-duty!
"""
config_type = self._settings_type
if not config_type:
config_type = get_type_hints(type(self)).get('settings', None)
self._settings_type = config_type # Cache config-type.
if config_type is None:
raise XynRestError(
f"BaseClient subclass type is undefined for model class ({self.model_type}), "
f"a type-hint for 'client' on BaseApi class must be in place for me to know "
f"what type to get."
)
return XContext.current(for_type=config_type)
# PyCharm has some sort of issue, if I provide property type-hint and then a property function
# that implements it. For some reason, this makes it ignore the type-hint in subclasses
# but NOT in the current class. It's some sort of bug. This gets around it since pycharm
# can't figure out what's going on here.
auth = _auth
settings = _settings
Classes
class RestApi (*, api: BaseApi[M] = None, model: BaseModel = None)-
Base
xynlib.orm.base.api.BaseApisubclass generally used by Rest API's.Things specific and common to rest api's should go in this class.
See parent
xynlib.orm.base.api.BaseApifor things in common among all API's.Warning: You can probably skip the rest (below)
Most of the time you don't create
BaseApiobjects your self, and so for most people you can skip the following unless you want to know more about internal details.Init Method Specifics
Normally you would not create an
BaseApiobject directly your self.BaseModel's know how to do this automatically. It happens inBaseModel.__init_subclass__().Details about how the arguments you can pass are below.
BaseModel Class Construction:
If you provide an
apiarg without amodelarg; we will copy theBaseApi.structureinto new object, resetting the error status, and internalBaseApi._stateto None. Thisapiobject is supposed to be the parent BaseModel's class api object.If both
apiarg +modelarg areNone, the BaseModel is the root/generic BaseModel (ie: it has no parent BaseModel).This is what is done by BaseModel classes while the class is lazily loading and creating/configuring the BaseModel class and it's associated
BaseApiobject (accessible viaBaseModel.api)BaseModel Instance Creation:
If you also pass in a
modelarg; this get you a special copy of the api you passed in for use just with that BaseModel instance. The modelBaseApi._statewill be allocated internally in the init'd BaseApi object. This is how aBaseModelinstance get's it's own associatedBaseApiobject (that's a different instance vs the one set on BaseModel class when the BaseModel class was originally constructed).All params are optional.
Args
api-
The "parent" BaseApi obj to copy the basic structure from as a starting point, etc. The superclasses BaseApi class is passed via this arg. This is only used when allocating a new
BaseApiobject for a newBaseModelclass (not an instance, a model class/type). This BaseApi object is used for the class-level BaseModel api object; ie: via "ModelClass.api"See above "BaseModel Class Construction" for more details.
model-
BaseModel to associate new BaseApi obj with. This is only used to create a new BaseApi object for a
BaseModelinstance for an already-existing type. ie: for BaseModel object instances.See above "BaseModel Instance Creation" for more details.
Expand source code
class RestApi(RemoteApi[M]): """ Base `xynlib.orm.base.api.BaseApi` subclass generally used by Rest API's. Things specific and common to rest api's should go in this class. See parent `xynlib.orm.base.api.BaseApi` for things in common among all API's. """ # Telling system about the default/base rest types we want to use with `RestApi`. client: RestClient[M] structure: RestStructure[Field] auth: RestAuth settings: RestSettings # todo: decide if we should just remove the below, not strictly needed, more of a convenience. # # Only used for IDE so it knows what type should be here, not used to know which Model to # allocate object. # This is because RestModel will tell/pass this into RestApi via `__init__`, # it happens when a RestModel/BaseModel is created (in BaseModel.__init__). model: RestModel[M] def send(self, url: URLStr = None): """ REQUIRES associated model object [see self.model]. Convenience method to send this single object to API, it simply calls `xynlib.orm.base.client.Client.send_objs` with a single object in the list (via `xynlib.orm.base.api.BaseApi.model`). If you want to send multiple objects, call `xynlib.orm.base.client.Client.send_objs`. Example is below, it uses a made-up rest model called 'SomeRestModelSubclass'. (I did not provide all details it would need to use the made-up/imagained rest-api; trying to illisrate a basic point here is all. If you want more details on how to make a real full/valid rest-model subclass see #INSERT-README-LINK#.) >>> from xmodel_rest import RestModel >>> class SomeRestModelSubclass(RestModel, base_url="....etc...."): ... pass # Some attributes from the rest-api go here >>> obj1 = SomeRestModelSubclass() >>> obj2 = SomeRestModelSubclass() >>> RestModel.api.client.send_objs([obj1, obj2]) If you pass in a `url` paramater to the `send_objs` method, the url gets appended to the final constructed url before the url gets validated. If the url is validated, it will use that final url [with passed in `url` this appended]. For more information about how URL's are appended to each-other see: `xurls.url.URLMutable.append_url`. The response from API will update all the values on this object with the results of the change [all fields will be updated] and with the latest values from API. You can check for errors on model object via `xmodel.remote.api.response_state`, ie: >>> from xynlib.orm import BaseModel >>> obj: BaseModel >>> # Check response_state to see if it had an error: >>> obj.api.response_state.had_error False """ # Redirect to client.send_objs: self.client.send_objs([self.model], url=url) # This is a resource-type, see `def auth()` doc-comment below for more details. # Subclasses can override this type-hint, and `RestApi` will allocate the new # type instead automatically, on demand. # # The type-hints inform this class what type of objects to create when `auth` along # with other special attributes such as `client` and `structure` are needed/asked-for. # # You can override the type by making your own type-hint on a sub-class. # See xmodel.base.api.BaseApi and xmodel.remote.api.RemoteApi for its various special # type-hinted attributes for more details, it has more detailed comments/documentation on it. auth: RestAuth @property def _auth(self): """ Treated a `xyn_resaource.context.Resource`, a context resource for the purposes of sharing auth credentials. The type-hint assoicated with `auth: XYZ` will be used to grab a resource of that type from the current context each time we are asked. Thus resource is the auth object used by your `xmodel.base.client.BaseClient` subclass, (such as `xynlib.orm.rest.RestClient`), to set what type should be used for this, in your BaseClient sub-class, make a type-hint like below. Let's say you have an auth class you want to use: >>> import xmodel.base.auth >>> import xmodel >>> class MyCoolAuthClass(xmodel.base.auth.RelationAuth) ... pass You can set a type-hint for it like so, and it will be automatiaclly used when needed: >>> class MyApi(xmodel.RemoteApi): ... auth: MyCoolAuthClass Doing that is enough, `xynlib.orm.rest.RestClient` class will see the type-hint and will grab one of that type from the XContext and return it. In the example above, it would be a `MyCoolAuthClass` type. The type-hint is lazily cached in self for fast lookup in the future. To see details on what the Auth object should do, see `xmodel.base.auth.BaseAuth`. """ auth_type: Type[RestAuth] = self._auth_type if not auth_type: # Will get all type-hints, and ensure they are valid type refrences # (otherwise will error out) auth_type = get_type_hints(type(self)).get('auth', RestAuth) self._auth_type = auth_type # Auth has tokens we want to try and share, treat it as a resource. return auth_type.grab() _settings_type: Type[RestSettings] = None @property def _settings(self): """ The config object that this api uses, can be customized per-model. All you have to do is this to make it a different type: >>> import xmodel >>> >>> class MySettings(BaseSettings): ... my_custom_var: str = xmodel.ConfigVar( ... "MY_CUSTOM_ENVIRONMENTAL_VAR", ... "default" ... ) >>> class MyApi(xmodel.BaseApi[M]): ... settings: MySettings >>> class MyModel(xmodel.model.BaseModel['MyModel']): ... api: MyApi The type-hints are enough to tell the system what types to use. They also will tell any IDE in use about what type it should be, for type-completion. So it's sort of doing double-duty! """ config_type = self._settings_type if not config_type: config_type = get_type_hints(type(self)).get('settings', None) self._settings_type = config_type # Cache config-type. if config_type is None: raise XynRestError( f"BaseClient subclass type is undefined for model class ({self.model_type}), " f"a type-hint for 'client' on BaseApi class must be in place for me to know " f"what type to get." ) return XContext.current(for_type=config_type) # PyCharm has some sort of issue, if I provide property type-hint and then a property function # that implements it. For some reason, this makes it ignore the type-hint in subclasses # but NOT in the current class. It's some sort of bug. This gets around it since pycharm # can't figure out what's going on here. auth = _auth settings = _settingsAncestors
Class variables
var default_converters : Dict[Type[Any], Converter]-
Inherited from:
RemoteApi.default_convertersFor an overview of type-converts, see Type Converters Overview …
Instance variables
var auth : RestAuth-
Treated a
xyn_resaource.context.Resource, a context resource for the purposes of sharing auth credentials. The type-hint assoicated withauth: XYZwill be used to grab a resource of that type from the current context each time we are asked.Thus resource is the auth object used by your
xmodel.base.client.BaseClientsubclass, (such asxynlib.orm.rest.RestClient), to set what type should be used for this, in your BaseClient sub-class, make a type-hint like below.Let's say you have an auth class you want to use:
>>> import xmodel.base.auth >>> import xmodel >>> class MyCoolAuthClass(xmodel.base.auth.RelationAuth) ... passYou can set a type-hint for it like so, and it will be automatiaclly used when needed:
>>> class MyApi(xmodel.RemoteApi): ... auth: MyCoolAuthClassDoing that is enough,
xynlib.orm.rest.RestClientclass will see the type-hint and will grab one of that type from the XContext and return it. In the example above, it would be aMyCoolAuthClasstype.The type-hint is lazily cached in self for fast lookup in the future.
To see details on what the Auth object should do, see
xmodel.base.auth.BaseAuth.Expand source code
@property def _auth(self): """ Treated a `xyn_resaource.context.Resource`, a context resource for the purposes of sharing auth credentials. The type-hint assoicated with `auth: XYZ` will be used to grab a resource of that type from the current context each time we are asked. Thus resource is the auth object used by your `xmodel.base.client.BaseClient` subclass, (such as `xynlib.orm.rest.RestClient`), to set what type should be used for this, in your BaseClient sub-class, make a type-hint like below. Let's say you have an auth class you want to use: >>> import xmodel.base.auth >>> import xmodel >>> class MyCoolAuthClass(xmodel.base.auth.RelationAuth) ... pass You can set a type-hint for it like so, and it will be automatiaclly used when needed: >>> class MyApi(xmodel.RemoteApi): ... auth: MyCoolAuthClass Doing that is enough, `xynlib.orm.rest.RestClient` class will see the type-hint and will grab one of that type from the XContext and return it. In the example above, it would be a `MyCoolAuthClass` type. The type-hint is lazily cached in self for fast lookup in the future. To see details on what the Auth object should do, see `xmodel.base.auth.BaseAuth`. """ auth_type: Type[RestAuth] = self._auth_type if not auth_type: # Will get all type-hints, and ensure they are valid type refrences # (otherwise will error out) auth_type = get_type_hints(type(self)).get('auth', RestAuth) self._auth_type = auth_type # Auth has tokens we want to try and share, treat it as a resource. return auth_type.grab() var client : RestClient[~M]-
Inherited from:
RemoteApi.clientReturns an appropriate concrete
RemoteClientsubclass. We figure out the proper client object to use based on the type-hint for … var context : XContext-
Inherited from:
RemoteApi.contextBaseApi context to use when asking this object to send/delete/etc its self to/from service …
var have_changes : bool-
Inherited from:
RemoteApi.have_changesIs True if
self.json(only_include_changes=True)is not None; see json() method for more details. var model : BaseModel[~M]-
Inherited from:
RemoteApi.modelREQUIRES associated model object [see doc text below] …
var model_type : Type[~M]-
Inherited from:
RemoteApi.model_typeThe same BaseApi class is meant to be re-used for any number of Models, and so a BaseModel specifies it's BaseApi type as generic
BaseApi[M]. In … var options : ApiOptions[~M]-
Inherited from:
RemoteApi.optionsA set of options you can modify for the current context. If a particular option inside the options object is not set, Options object may look at the …
var response_state : ResponseState[~M]-
Inherited from:
RemoteApi.response_stateReturns the HTTP/Communication state of the api object …
var settings : RestSettings-
The config object that this api uses, can be customized per-model. All you have to do is this to make it a different type:
>>> import xmodel >>> >>> class MySettings(BaseSettings): ... my_custom_var: str = xmodel.ConfigVar( ... "MY_CUSTOM_ENVIRONMENTAL_VAR", ... "default" ... ) >>> class MyApi(xmodel.BaseApi[M]): ... settings: MySettings >>> class MyModel(xmodel.model.BaseModel['MyModel']): ... api: MyApiThe type-hints are enough to tell the system what types to use. They also will tell any IDE in use about what type it should be, for type-completion. So it's sort of doing double-duty!
Expand source code
@property def _settings(self): """ The config object that this api uses, can be customized per-model. All you have to do is this to make it a different type: >>> import xmodel >>> >>> class MySettings(BaseSettings): ... my_custom_var: str = xmodel.ConfigVar( ... "MY_CUSTOM_ENVIRONMENTAL_VAR", ... "default" ... ) >>> class MyApi(xmodel.BaseApi[M]): ... settings: MySettings >>> class MyModel(xmodel.model.BaseModel['MyModel']): ... api: MyApi The type-hints are enough to tell the system what types to use. They also will tell any IDE in use about what type it should be, for type-completion. So it's sort of doing double-duty! """ config_type = self._settings_type if not config_type: config_type = get_type_hints(type(self)).get('settings', None) self._settings_type = config_type # Cache config-type. if config_type is None: raise XynRestError( f"BaseClient subclass type is undefined for model class ({self.model_type}), " f"a type-hint for 'client' on BaseApi class must be in place for me to know " f"what type to get." ) return XContext.current(for_type=config_type) var structure : RestStructure[Field]-
Inherited from:
RemoteApi.structureContain things that don't vary among the model instances; ie: This is the same object and applies to all instances of a particular BaseModel class …
Methods
def delete(self)-
Inherited from:
RemoteApi.deleteREQUIRES associated model object [see self.model] …
def did_send(self)-
Inherited from:
RemoteApi.did_sendself.client will call us here after someone attempts to send us (a specific model), you and use
RelationApi.modelto grab the model that it happened … def fields_to_pop_for_json(self, json: dict, field_objs: List[Field], log_output: bool) ‑> Set[Any]-
Inherited from:
RemoteApi.fields_to_pop_for_jsonGoes through the list of fields (field_objs) to determine which ones have not changed in order to pop them out of the json representation. This method …
def forget_original_json_state(self)-
Inherited from:
RemoteApi.forget_original_json_stateIf called, we forget/reset the orginal json state, which is a combination of all the json that this object has been updated with over it's lifetime …
def get(self, query: Dict[str, Union[str, int, datetime.date, xurls.url._FormattedQueryValue, None, Iterable[Union[str, int, datetime.date, xurls.url._FormattedQueryValue]]]] = None, *, top: int = None, fields: Optional[Sequence[str]] = Default) ‑> Optional[Iterable[~M]]-
Important: Right now we return a list, but it might be just a generator in the future, treat the return type as a true Iterable, something you can't …
def get_child_without_lazy_lookup(self, child_field_name, *, false_if_not_set=False) ‑> Union[BaseModel[~M], None, bool, NullType]-
Inherited from:
RemoteApi.get_child_without_lazy_lookupREQUIRES associated model object [see self.model] …
def get_via_id(self, id: Union[int, str, List[Union[int, str]], Dict[str, Union[str, int]], List[Dict[str, Union[str, int]]]], fields: Sequence[str] = Default, id_field: str = None, aux_query: Dict[str, Union[str, int, datetime.date, xurls.url._FormattedQueryValue, None, Iterable[Union[str, int, datetime.date, xurls.url._FormattedQueryValue]]]] = None) ‑> Union[Iterable[~M], ~M, None]-
Inherited from:
RemoteApi.get_via_idThis method would have probably been better named
get_via_key… def json(self, only_include_changes: bool = False, log_output: bool = False) ‑> Optional[Dict[str, Any]]-
Inherited from:
RemoteApi.jsonBaseApi.json()to see superclass's documentation for this method … def list_of_attrs_to_repr(self) ‑> List[str]-
Inherited from:
RemoteApi.list_of_attrs_to_repr" REQUIRES associated model object [see self.model] …
def option_all_for_name(self, option_attribute_name) ‑> List[Any]-
Inherited from:
RemoteApi.option_all_for_nameGets a particular option attribute by name in a particular prioritized order …
def option_for_name(self, option_attribute_name) ‑> Any-
Inherited from:
RemoteApi.option_for_nameReturns the first option returned from self.option_all_for_name for the
option_attribute_namethat is passed in; otherwise None … def send(self, url: Union[str, URL, None] = None)-
REQUIRES associated model object [see self.model].
Convenience method to send this single object to API, it simply calls
xynlib.orm.base.client.Client.send_objswith a single object in the list (viaxynlib.orm.base.api.BaseApi.model).If you want to send multiple objects, call
xynlib.orm.base.client.Client.send_objs.Example is below, it uses a made-up rest model called 'SomeRestModelSubclass'.
(I did not provide all details it would need to use the made-up/imagained rest-api; trying to illisrate a basic point here is all. If you want more details on how to make a real full/valid rest-model subclass see #INSERT-README-LINK#.)
>>> from xmodel_rest import RestModel >>> class SomeRestModelSubclass(RestModel, base_url="....etc...."): ... pass # Some attributes from the rest-api go here >>> obj1 = SomeRestModelSubclass() >>> obj2 = SomeRestModelSubclass() >>> RestModel.api.client.send_objs([obj1, obj2])If you pass in a
urlparamater to thesend_objsmethod, the url gets appended to the final constructed url before the url gets validated.If the url is validated, it will use that final url [with passed in
urlthis appended]. For more information about how URL's are appended to each-other see:URLMutable.append_url().The response from API will update all the values on this object with the results of the change [all fields will be updated] and with the latest values from API.
You can check for errors on model object via
xmodel.remote.api.response_state, ie:>>> from xynlib.orm import BaseModel >>> obj: BaseModel >>> # Check response_state to see if it had an error: >>> obj.api.response_state.had_error FalseExpand source code
def send(self, url: URLStr = None): """ REQUIRES associated model object [see self.model]. Convenience method to send this single object to API, it simply calls `xynlib.orm.base.client.Client.send_objs` with a single object in the list (via `xynlib.orm.base.api.BaseApi.model`). If you want to send multiple objects, call `xynlib.orm.base.client.Client.send_objs`. Example is below, it uses a made-up rest model called 'SomeRestModelSubclass'. (I did not provide all details it would need to use the made-up/imagained rest-api; trying to illisrate a basic point here is all. If you want more details on how to make a real full/valid rest-model subclass see #INSERT-README-LINK#.) >>> from xmodel_rest import RestModel >>> class SomeRestModelSubclass(RestModel, base_url="....etc...."): ... pass # Some attributes from the rest-api go here >>> obj1 = SomeRestModelSubclass() >>> obj2 = SomeRestModelSubclass() >>> RestModel.api.client.send_objs([obj1, obj2]) If you pass in a `url` paramater to the `send_objs` method, the url gets appended to the final constructed url before the url gets validated. If the url is validated, it will use that final url [with passed in `url` this appended]. For more information about how URL's are appended to each-other see: `xurls.url.URLMutable.append_url`. The response from API will update all the values on this object with the results of the change [all fields will be updated] and with the latest values from API. You can check for errors on model object via `xmodel.remote.api.response_state`, ie: >>> from xynlib.orm import BaseModel >>> obj: BaseModel >>> # Check response_state to see if it had an error: >>> obj.api.response_state.had_error False """ # Redirect to client.send_objs: self.client.send_objs([self.model], url=url) def should_include_field_in_json(self, new_value: Any, old_value: Any, field: str) ‑> bool-
Inherited from:
RemoteApi.should_include_field_in_jsonReturns True if the the value for field should be included in the JSON. This only gets called if only_include_changes is True when passed to …
def update_from_json(self, json: Union[Dict[str, Any], Mapping[~KT, +VT_co]])-
Inherited from:
RemoteApi.update_from_jsonBaseApi.update_from_json()to see superclass's documentation for this method …