Skip to main content

Fournit quelques méthodes de récupération d'objet en base autour d'SQLAlchemy

Project description

('Helpers SQLAlchemy - :class:`sqla_helpers.base_model.BaseModel`\n===============================================================\nInstallation\n-------------\n\n.. rubric:: Git\n\nInstallation depuis le d\xc3\xa9p\xc3\xb4t git\n\n.. code-block:: console\n\n $> git clone git@github.com:moumoutte/sqla_helpers.git\n $> cd sqla_helpers\n $> sudo python2.7 setup.py install\n\n.. rubric:: Eggs\n\nInstallation depuis les archives `eggs`\n\n.. code-block:: console\n\n $> sudo pip install sqla_helpers\n\n\nGetting Started\n----------------\n\n:class:`sqla_helpers.base_model.BaseModel` a pour but d\'instrumenter la syntaxe d\'SQLAlchemy pour\nfournir \xc3\xa0 l\'utiliseur final, des m\xc3\xa9thodes simplifi\xc3\xa9es permettant la r\xc3\xa9cup\xc3\xa9ration\nd\'objets en base.\n\n:class:`sqla_helpers.base_model.BaseModel` est une classe qui est utilisable en tant que Mixin, elle\nn\'h\xc3\xa9rite d\'aucune classe et elle n\'est pas \xc3\xa0 sous-classer.\nPour avoir acc\xc3\xa8s aux m\xc3\xa9thodes dans un mod\xc3\xa8le, il faut alors d\xc3\xa9clarer une table\ncomme ceci:\n\n.. code-block:: python\n\n from somewhere import DeclarativeBase\n from sqla_helpers.base_model import BaseModel\n\n class MyModel(DeclarativeBase, BaseModel):\n id = ... # Clef primaire , l\'identifiant sous forme d\'entier\n awesome_attr = ... # Attribut quelconque du mod\xc3\xa8le\n other_model = relationship(\'MyOtherModel\', backref=\'mymodel\')\n\n\n class MyOtherModel(DeclarativeBase, BaseModel):\n id = ... # Clef primaire\n name = ...\n model_id = ... # Clef \xc3\xa9trang\xc3\xa8re sur MyModel\n\n\nLa classe :class:`DeclarativeBase` est la classe g\xc3\xa9n\xc3\xa9r\xc3\xa9e par la fonction\n:func:`declarative_base` d\'SQLAlchemy.\n\nIl est \xc3\xa9galement possible d\'utiliser :class:`sqla_helpers.base_model.BaseModel` comme param\xc3\xa8tre `cls` de la fonction :func:`declarative_base`.\nEt ainsi on peut se passer de l\'utilisation de la classe comme Mixin.\n\n\n.. code-block:: python\n\n from sqlalchemy.ext.declarative import declarative_base\n from sqla_helpers.base_model import BaseModel\n DeclarativeBase = declarative_base(cls=BaseModel)\n\n\n.. code-block:: python\n\n class MyModel(DeclarativeBase):\n # ...\n\n\n:class:`sqla_helpers.base_model.BaseModel` attend une mani\xc3\xa8re de r\xc3\xa9cup\xc3\xa9rer une session quand une requ\xc3\xaate est effectu\xc3\xa9e.\nPour ce faire, elle fait appel \xc3\xa0 la fonction stock\xc3\xa9e dans l\'attribut :attr:`sqla_helpers.base_model.BaseModel.sessionmaker`.\nAinsi, lors de l\'initialisation de l\'application, il faut stocker un\nsessionmaker dans la classe, gr\xc3\xa2ce \xc3\xa0 la m\xc3\xa9thode\n`sqla_helpers.base_model.BaseModel.register_sessionmaker`\n\n.. code-block:: python\n\n # Initialisation de l\'application\n def main():\n # ...\n BaseModel.register_sessionmaker(scoped_session(sessionmaker(bind=engine)))\n # ...\n\n\nPour passer une session globale, il suffit simplement que la fonction pass\xc3\xa9e \xc3\xa0 :attr:`sqla_helpers.base_model.BaseModel.sessionmaker`\nrenvoie la r\xc3\xa9f\xc3\xa9rence sur la session globale\n\n.. code-block:: python\n\n from somwhere import DBSession\n\n # Initialisation de l\'application\n def main():\n # ...\n BaseModel.register_sessionmaker(lambda: DBSession)\n # ...\n\n\nCas d\'utilisation simple :\n\n.. code-block:: python\n\n >>> MyModel.all()\n [<MyModel object at 0x2c19d90>]\n >>> MyModel.get(id=2)\n <MyModel object at 0x2c19d90>\n >>> MyModel.get(id=3)\n *** NoResultFound: No row was found for one()\n >>> MyModel.filter(id=2)\n [<MyModel object at 0x2c19d90>]\n >>> MyModel.filter(id=3)\n []\n\n\n* :meth:`sqla_helpers.base_model.BaseModel.all` ram\xc3\xa8ne l\'ensemble des objets en base.\n* :meth:`sqla_helpers.base_model.BaseModel.filter` ram\xc3\xa8ne les objets correspondants aux crit\xc3\xa8res donn\xc3\xa9s sous forme de liste.\n* :meth:`sqla_helpers.base_model.BaseModel.get` ram\xc3\xa8ne un unique \xc3\xa9l\xc3\xa9ment correspond aux crit\xc3\xa8res donn\xc3\xa9es.\n\nOn peut bien \xc3\xa9videmment encha\xc3\xaener les crit\xc3\xa8res de recherche qui seront pris en\ncompte avec un op\xc3\xa9rateur `&&` (ET) logique.\n\n.. code-block:: python\n\n >>> MyOtherModel.filter(name=\'toto\')\n [<MyOtherModel object at 0x2c19d90>, <MyOtherModel object at 0x2e27e08>]\n >>> MyOtherModel.filter(name=\'toto\', id=2)\n [<MyOtherModel object at 0x2c19d90>]\n\n\nRecherche sur crit\xc3\xa8res de relation\n----------------------------------\n\nLes crit\xc3\xa8res de recherche valides pour une classe sont d\xc3\xa9finies par ses\nattributs (Pour MyOtherModel \xc3\xa7a sera `id`, `name`, `model_id`).\n\nCela est \xc3\xa9galement valable pour le relation SQLAlchemy.\n\nPar exemple, on peut rechercher tous les MyModel dont le MyOtherModel a pour nom\n\'toto\'\n\n.. code-block:: python\n\n >>> MyModel.filter(awesome_attr__name=\'toto\')\n [<MyModel object at 0x2c19d90>]\n\n\nOn peut m\xc3\xaame rechercher suivant un objet complet.\n\n.. code-block:: python\n\n >>> otherModel = MyOtherModel.get(name=\'toto\')\n >>> MyModel.filter(awesome_attr=otherModel)\n [<MyModel object at 0x2c19d90>]\n\n\nLe s\xc3\xa9parateur `__` (double underscore) permet de faire la s\xc3\xa9paration entre les\ndiff\xc3\xa9rentes entit\xc3\xa9s sollicit\xc3\xa9es.\n\nLa recherche par les attributs des relations peut se faire en profondeur.\nImaginons que `MyOtherObject` est un attribut `other_attr` qui est en relation\navec un objet MyOtherOtherObject.\n\nIl est alors possible de rechercher tous les MyModel dont le MyOtherObject a un\nMyOtherOtherObject dont le nom est \'toto\'.\n\n.. code-block:: python\n\n >>> MyModel.filter(awesome_attr__other_attr__name=\'toto\')\n [<MyModel object at 0x2c19d90>]\n\n\n\nDes op\xc3\xa9rateurs\n--------------\n\nIl est possible de sp\xc3\xa9cifier d\'autres crit\xc3\xa8res que ceux d\'\xc3\xa9galit\xc3\xa9s. En s\xc3\xa9parant\nencore une fois, avec des \'__\' (doubles underscores) et en mettant le nom de\nl\'op\xc3\xa9rateur \xc3\xa0 la fin du crit\xc3\xa8re.\n\nPar exemple, si l\'on veut tous les MyModel qui n\'ont PAS pour id la valeur 2.\n\n.. code-block:: python\n\n >>> MyModel.filter(id__not=2)\n []\n\nLes op\xc3\xa9rateurs disponibles sont :\n\n* \'not\': Non-\xc3\xa9gal\n* \'lt\': inf\xc3\xa9rieur\n* \'le\': Inf\xc3\xa9rieur ou \xc3\xa9gal\n* \'gt\': Plus grand\n* \'gte\': Plus grand ou \xc3\xa9gal\n* \'in\': Contenu dans (Le param\xc3\xa8tre de recherche doit-\xc3\xaatre une liste)\n* \'like\': op\xc3\xa9rateur SQL LIKE\n* \'ilike\': op\xc3\xa9rateur SQL ILIKE\n\n\nRequ\xc3\xaates plus complexes\n-----------------------\n\nToujours sur le mod\xc3\xa8le de Django, :mod:`sqla_helpers` fournit un :class:`sqla_helpers.logical.Q` object afin de pouvoir r\xc3\xa9aliser des op\xc3\xa9ration un peu plus complexes\nLe :class:`sqla_helpers.logical.Q` object est capable de prendre ne compte la\nsyntaxe sqla_helpers.\n\n.. code-block:: python\n\n >>> from sqla_helpers.logical import Q\n >>> Q(status__name=\'test\')\n <sqla_helpers.logical.Q at 0x2376cd0>\n\n\nCes objets sont transmissibles aux m\xc3\xa9thodes de recherches de la classe\n:class:`sqla_helpers.base_model.BaseModel`\n\n.. code-block:: python\n\n >>> Treatment.get(Q(id=2))\n >>> <sqlalchemy_test.models.Treatment at 0x2388690>\n\nL\'avantage de ces objets, c\'est qu\'ils permettent de d\xc3\xa9crire des conditions\nlogiques SQL \xc3\xa0 travers une syntaxe python.\n\nSi l\'on veut les traitments qui ont pour id 2 OU le status \xc3\xa0 pour nom \'KO\'\n\n.. code-block:: python\n\n >>> Treatment.filter(Q(id=2) | Q(status__name=\'KO\'))\n [<sqlalchemy_test.models.Treatment at 0x2388690>, <sqlalchemy_test.models.Treatment at 0x23837d0>]\n\n\nSi l\'on veut tous les traitments qui n\'ont pas pour id 2\n\n.. code-block:: python\n\n >>> Treatment.filter(~Q(id=2))\n [<sqlalchemy_test.models.Treatment at 0x2383450>, <sqlalchemy_test.models.Treatment at 0x23837d0>,\n <sqlalchemy_test.models.Treatment at 0x23886d0> ]\n\nMais on peut \xc3\xa9galement enchainer les op\xc3\xa9rations logiques\n\n.. code-block:: python\n\n >>> Treatment.filter((Q(id=2) | Q(name=\'toto\')) & (Q(name=\'OK\') | ~Q(status__id=3)))\n 2013-02-10 16:39:49,485 INFO sqlalchemy.engine.base.Engine SELECT\n treatment.id AS treatment_id, treatment.name AS treatment_name,\n treatment.status_id AS treatment_status_id\n FROM treatment JOIN status ON status.id = treatment.status_id\n WHERE (treatment.id = ? OR treatment.name = ?) AND (treatment.name = ? OR\n status.id != ?)\n 2013-02-10 16:39:49,485 INFO sqlalchemy.engine.base.Engine (2, \'toto\', \'OK\',\n 3)\n >>> [<sqlalchemy_test.models.Treatment at 0x2388690>]\n\n\nDu JSON\n-------\n\nSouvent dans les applications web, le client et le serveur communique par l\'interm\xc3\xa9diaire du format JSON.\nPour faciliter les op\xc3\xa9rations de chargement, :mod:`sqla_helpers` fournit des\nm\xc3\xa9thodes permettant de charger des objets mod\xc3\xa8les depuis un dictionnaire python ou bien de g\xc3\xa9n\xc3\xa9rer un dictionnaire depuis un objet mod\xc3\xa8le SQLALchemy.\n\nLa m\xc3\xa9thode :meth:`sqla_helpers.base_model.BaseModel.dump` permet la g\xc3\xa9n\xc3\xa9ration d\'un dictionnaire qui est transformable en JSON.\n\n.. code-block:: python\n\n >>> print json.dumps(t.dump(), indent=4)\n {\n "status": {\n "id": 1,\n "name": "Ok"\n },\n "status_id": 1,\n "id": 1,\n "name": "Great Treatment"\n }\n\n\nEt la m\xc3\xa9thode de classe `sqla_helpers.base_model.BaseModel.load` qui permet d\'instancier des objets \xc3\xa0 partir d\'un dictionnaire.\nLe passage par dictionnaire est sens\xc3\xa9 faciliter l\'acc\xc3\xa8s aux donn\xc3\xa9es en JSON ou bien g\xc3\xa9n\xc3\xa9rer du JSON depuis le\ndictionnaire.\n\nPour le chargement d\'un objet, les objets sont r\xc3\xa9cup\xc3\xa9r\xc3\xa9s en base si les attributs composant la clef primaire\nsont trouv\xc3\xa9s dans le dictionnaire. Sinon, une nouvelle instance est cr\xc3\xa9\xc3\xa9e.\n\n.. code-block:: python\n\n >>> t = Treatment.get(id=7)\n >>> t.name\n \'YEAH \\\\o/\'\n >>> t.id\n 7\n >>> t.status.name\n \'Sacre status !\'\n >>> t.status.id\n 7\n >>> t = Treatment.load({\'id\': 7, \'name\': \'hello\'})\n >>> t.name, t.id\n (\'hello\', 7)\n >>> session.commit()\n >>> t.dump()\n {\n \'id\': 7,\n \'name\': u\'hello\',\n \'status\': {\'id\': 7, \'name\': u\'Sacre status !\'},\n \'status_id\': 7\n }\n >>> tr = Treatment.load(t.dump())\n >>> tr == t\n True\n >>> tr.status == t.status\n True\n >>> Treatment.load(tr.dump()).dump()\n {\n \'id\': 7,\n \'name\': u\'hello\',\n \'status\': {\'id\': 7, \'name\': u\'Sacre status !\'},\n \'status_id\': 7\n }\n >>> tr = Treatment.load({\'name\': \'nouveau traitmente\', \'status\': {\'name\': \'nouveau status\'}})\n >>> tr.id\n None\n >>> tr.status.id\n None\n >>> session.add(tr)\n >>> session.commit()\n >>> tr.id\n 10\n >>> tr.status.id\n 8\n\n\nLa classe :class:`sqla_helpers.base_model.BaseModel`\n====================================================\n\n.. automodule:: sqla_helpers.base_model\n',)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqla_helpers-0.3.4.tar.gz (14.9 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page