Metadata-Version: 1.1
Name: sqla_helpers
Version: 0.3.2
Summary: Fournit quelques méthodes de récupération d'objet en base autour d'SQLAlchemy
Home-page: https://github.com/moumoutte/sqla_helpers/
Author: Guillaume Camera
Author-email: camera.g@gmail.com
License: UNKNOWN
Description: Helpers SQLAlchemy - :class:`sqla_helpers.base_model.BaseModel`
        ===============================================================
        Installation
        -------------
        
        .. rubric:: Git
        
        Installation depuis le dépôt git
        
        .. code-block:: console
        
                $> git clone git@github.com:moumoutte/sqla_helpers.git
                $> cd sqla_helpers
                $> sudo python2.7 setup.py install
        
        .. rubric:: Eggs
        
        Installation depuis les archives `eggs`
        
        .. code-block:: console
        
                $> sudo pip install sqla_helpers
        
        
        Getting Started
        ----------------
        
        :class:`sqla_helpers.base_model.BaseModel` a pour but d'instrumenter la syntaxe d'SQLAlchemy pour
        fournir à l'utiliseur final, des méthodes simplifiées permettant la récupération
        d'objets en base.
        
        :class:`sqla_helpers.base_model.BaseModel` est une classe qui est utilisable en tant que Mixin, elle
        n'hérite d'aucune classe et elle n'est pas à sous-classer.
        Pour avoir accès aux méthodes dans un modèle, il faut alors déclarer une table
        comme ceci:
        
        .. code-block:: python
        
            from somewhere import DeclarativeBase
            from sqla_helpers.base_model import BaseModel
        
            class MyModel(DeclarativeBase, BaseModel):
                id = ... # Clef primaire , l'identifiant sous forme d'entier
                awesome_attr = ... # Attribut quelconque du modèle
                other_model = relationship('MyOtherModel', backref='mymodel')
        
        
            class MyOtherModel(DeclarativeBase, BaseModel):
                id = ... # Clef primaire
                name = ...
                model_id = ... # Clef étrangère sur MyModel
        
        
        La classe :class:`DeclarativeBase` est la classe générée par la fonction
        :func:`declarative_base` d'SQLAlchemy.
        
        Il est également possible d'utiliser :class:`sqla_helpers.base_model.BaseModel` comme paramètre `cls` de la fonction :func:`declarative_base`.
        Et ainsi on peut se passer de l'utilisation de la classe comme Mixin.
        
        
        .. code-block:: python
        
            from sqlalchemy.ext.declarative import declarative_base
            from sqla_helpers.base_model import BaseModel
            DeclarativeBase = declarative_base(cls=BaseModel)
        
        
        .. code-block:: python
        
            class MyModel(DeclarativeBase):
                # ...
        
        
        :class:`sqla_helpers.base_model.BaseModel` attend une manière de récupérer une session quand une requête est effectuée.
        Pour ce faire, elle fait appel à la fonction stockée dans l'attribut :attr:`sqla_helpers.base_model.BaseModel.sessionmaker`.
        Ainsi, lors de l'initialisation de l'application, il faut stocker un
        sessionmaker dans la classe, grâce à la méthode
        `sqla_helpers.base_model.BaseModel.register_sessionmaker`
        
        .. code-block:: python
        
            # Initialisation de l'application
            def main():
                # ...
                BaseModel.register_sessionmaker(scoped_session(sessionmaker(bind=engine)))
                # ...
        
        
        Pour passer une session globale, il suffit simplement que la fonction passée à :attr:`sqla_helpers.base_model.BaseModel.sessionmaker`
        renvoie la référence sur la session globale
        
        .. code-block:: python
        
            from somwhere import DBSession
        
            # Initialisation de l'application
            def main():
                # ...
                BaseModel.register_sessionmaker(lambda: DBSession)
                # ...
        
        
        Cas d'utilisation simple :
        
        .. code-block:: python
        
            >>> MyModel.all()
            [<MyModel object at 0x2c19d90>]
            >>> MyModel.get(id=2)
            <MyModel object at 0x2c19d90>
            >>> MyModel.get(id=3)
            *** NoResultFound: No row was found for one()
            >>> MyModel.filter(id=2)
            [<MyModel object at 0x2c19d90>]
            >>> MyModel.filter(id=3)
            []
        
        
        * :meth:`sqla_helpers.base_model.BaseModel.all` ramène l'ensemble des objets en base.
        * :meth:`sqla_helpers.base_model.BaseModel.filter` ramène les objets correspondants aux critères donnés sous forme de liste.
        * :meth:`sqla_helpers.base_model.BaseModel.get` ramène un unique élément correspond aux critères données.
        
        On peut bien évidemment enchaîner les critères de recherche qui seront pris en
        compte avec un opérateur `&&` (ET) logique.
        
        .. code-block:: python
        
            >>> MyOtherModel.filter(name='toto')
            [<MyOtherModel object at 0x2c19d90>, <MyOtherModel object at 0x2e27e08>]
            >>> MyOtherModel.filter(name='toto', id=2)
            [<MyOtherModel object at 0x2c19d90>]
        
        
        Recherche sur critères de relation
        ----------------------------------
        
        Les critères de recherche valides pour une classe sont définies par ses
        attributs (Pour MyOtherModel ça sera `id`, `name`, `model_id`).
        
        Cela est également valable pour le relation SQLAlchemy.
        
        Par exemple, on peut rechercher tous les MyModel dont le MyOtherModel a pour nom
        'toto'
        
        .. code-block:: python
        
            >>> MyModel.filter(awesome_attr__name='toto')
            [<MyModel object at 0x2c19d90>]
        
        
        On peut même rechercher suivant un objet complet.
        
        .. code-block:: python
        
            >>> otherModel = MyOtherModel.get(name='toto')
            >>> MyModel.filter(awesome_attr=otherModel)
            [<MyModel object at 0x2c19d90>]
        
        
        Le séparateur `__` (double underscore) permet de faire la séparation entre les
        différentes entités sollicitées.
        
        La recherche par les attributs des relations peut se faire en profondeur.
        Imaginons que `MyOtherObject` est un attribut `other_attr` qui est en relation
        avec un objet MyOtherOtherObject.
        
        Il est alors possible de rechercher tous les MyModel dont le MyOtherObject a un
        MyOtherOtherObject dont le nom est 'toto'.
        
        .. code-block:: python
        
            >>> MyModel.filter(awesome_attr__other_attr__name='toto')
            [<MyModel object at 0x2c19d90>]
        
        
        
        Des opérateurs
        --------------
        
        Il est possible de spécifier d'autres critères que ceux d'égalités. En séparant
        encore une fois, avec des '__' (doubles underscores) et en mettant le nom de
        l'opérateur à la fin du critère.
        
        Par exemple, si l'on veut tous les MyModel qui n'ont PAS pour id la valeur 2.
        
        .. code-block:: python
        
            >>> MyModel.filter(id__not=2)
            []
        
        Les opérateurs disponibles sont :
        
        * 'not': Non-égal
        * 'lt': inférieur
        * 'le': Inférieur ou égal
        * 'gt': Plus grand
        * 'gte': Plus grand ou égal
        * 'in': Contenu dans (Le paramètre de recherche doit-être une liste)
        * 'like': opérateur SQL LIKE
        * 'ilike': opérateur SQL ILIKE
        
        
        Requêtes plus complexes
        -----------------------
        
        Toujours sur le modèle de Django, :mod:`sqla_helpers` fournit un :class:`sqla_helpers.logical.Q` object afin de pouvoir réaliser des opération un peu plus complexes
        Le :class:`sqla_helpers.logical.Q` object est capable de prendre ne compte la
        syntaxe sqla_helpers.
        
        .. code-block:: python
        
            >>> from sqla_helpers.logical import Q
            >>> Q(status__name='test')
            <sqla_helpers.logical.Q at 0x2376cd0>
        
        
        Ces objets sont transmissibles aux méthodes de recherches de la classe
        :class:`sqla_helpers.base_model.BaseModel`
        
        .. code-block:: python
        
            >>> Treatment.get(Q(id=2))
            >>> <sqlalchemy_test.models.Treatment at 0x2388690>
        
        L'avantage de ces objets, c'est qu'ils permettent de décrire des conditions
        logiques SQL à travers une syntaxe python.
        
        Si l'on veut les traitments qui ont pour id 2 OU le status à pour nom 'KO'
        
        .. code-block:: python
        
            >>>  Treatment.filter(Q(id=2) | Q(status__name='KO'))
            [<sqlalchemy_test.models.Treatment at 0x2388690>, <sqlalchemy_test.models.Treatment at 0x23837d0>]
        
        
        Si l'on veut tous les traitments qui n'ont pas pour id 2
        
        .. code-block:: python
        
            >>> Treatment.filter(~Q(id=2))
            [<sqlalchemy_test.models.Treatment at 0x2383450>, <sqlalchemy_test.models.Treatment at 0x23837d0>,
              <sqlalchemy_test.models.Treatment at 0x23886d0> ]
        
        Mais on peut également enchainer les opérations logiques
        
        .. code-block:: python
        
            >>> Treatment.filter((Q(id=2) | Q(name='toto')) & (Q(name='OK') | ~Q(status__id=3)))
            2013-02-10 16:39:49,485 INFO sqlalchemy.engine.base.Engine SELECT
            treatment.id AS treatment_id, treatment.name AS treatment_name,
            treatment.status_id AS treatment_status_id
            FROM treatment JOIN status ON status.id = treatment.status_id
            WHERE (treatment.id = ? OR treatment.name = ?) AND (treatment.name = ? OR
            status.id != ?)
            2013-02-10 16:39:49,485 INFO sqlalchemy.engine.base.Engine (2, 'toto', 'OK',
            3)
            >>> [<sqlalchemy_test.models.Treatment at 0x2388690>]
        
        
        Du JSON
        -------
        
        Souvent dans les applications web, le client et le serveur communique par l'intermédiaire du format JSON.
        Pour faciliter les opérations de chargement, :mod:`sqla_helpers` fournit des
        méthodes permettant de charger des objets modèles depuis un dictionnaire python ou bien de générer un dictionnaire depuis un objet modèle SQLALchemy.
        
        La méthode :meth:`sqla_helpers.base_model.BaseModel.dump` permet la génération d'un dictionnaire qui est transformable en JSON.
        
        .. code-block:: python
        
                >>> print json.dumps(t.dump(), indent=4)
                {
                    "status": {
                        "id": 1,
                        "name": "Ok"
                    },
                    "status_id": 1,
                    "id": 1,
                    "name": "Great Treatment"
                }
        
        
        Et la méthode de classe `sqla_helpers.base_model.BaseModel.load` qui permet d'instancier des objets à partir d'un dictionnaire.
        Le passage par dictionnaire est sensé faciliter l'accès aux données en JSON ou bien générer du JSON depuis le
        dictionnaire.
        
        Pour le chargement d'un objet, les objets sont récupérés en base si les attributs composant la clef primaire
        sont trouvés dans le dictionnaire. Sinon, une nouvelle instance est créée.
        
        .. code-block:: python
        
                >>> t = Treatment.get(id=7)
                >>> t.name
                'YEAH \\o/'
                >>> t.id
                7
                >>> t.status.name
                'Sacre status !'
                >>> t.status.id
                7
                >>> t = Treatment.load({'id': 7, 'name': 'hello'})
                >>> t.name, t.id
                ('hello', 7)
                >>> session.commit()
                >>> t.dump()
                {
                        'id': 7,
                        'name': u'hello',
                        'status': {'id': 7, 'name': u'Sacre status !'},
                        'status_id': 7
                }
                >>> tr = Treatment.load(t.dump())
                >>> tr == t
                True
                >>> tr.status == t.status
                True
                >>> Treatment.load(tr.dump()).dump()
                {
                        'id': 7,
                        'name': u'hello',
                        'status': {'id': 7, 'name': u'Sacre status !'},
                        'status_id': 7
                }
                >>> tr = Treatment.load({'name': 'nouveau traitmente', 'status': {'name': 'nouveau status'}})
                >>> tr.id
                None
                >>> tr.status.id
                None
                >>> session.add(tr)
                >>> session.commit()
                >>> tr.id
                10
                >>> tr.status.id
                8
        
        
        La classe :class:`sqla_helpers.base_model.BaseModel`
        ====================================================
        
        .. autoclass:: sqla_helpers.base_model.BaseModel
          :members:
        
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: License :: OSI Approved :: BSD License
Classifier: Natural Language :: French
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.7
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires: nose
Requires: coverage
Requires: mock
Requires: sqlalchemy
