{"id":15664899,"url":"https://github.com/genaker/pygento","last_synced_at":"2025-05-06T19:41:08.231Z","repository":{"id":99663255,"uuid":"415814326","full_name":"Genaker/PyGento","owner":"Genaker","description":"Python module to work with Magneto Database directly without using broken Magento 2 core ","archived":false,"fork":false,"pushed_at":"2024-04-03T00:24:05.000Z","size":263,"stargazers_count":18,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-04T13:44:24.482Z","etag":null,"topics":["activerecord","database","magento","magento2","microservices","mysql","orm","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Genaker.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-10-11T07:05:08.000Z","updated_at":"2024-05-17T09:56:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"99c20156-b9ac-49a5-98cc-3ef853784746","html_url":"https://github.com/Genaker/PyGento","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FPyGento","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FPyGento/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FPyGento/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FPyGento/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Genaker","download_url":"https://codeload.github.com/Genaker/PyGento/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221154145,"owners_count":16765379,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","database","magento","magento2","microservices","mysql","orm","python"],"created_at":"2024-10-03T13:44:28.384Z","updated_at":"2024-10-23T04:04:27.539Z","avatar_url":"https://github.com/Genaker.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PyGento\nPython module to work with Magneto Database directly without using broken Magento 2 core\n\n\u003cimg src=\"https://github.com/Genaker/PyGento/blob/main/PyGento.PNG?raw=true\" alt=\"PyGento\" width=\"600\"/\u003e\n\nPyGento is built on top of the SQL Alchemy\n\nSQLAlchemy is a library that facilitates the communication between Python programs and Magento databases. This library  acts as an Object Relational Mapper (ORM) tool that translates Python classes to Magento tables and automatically converts function calls to SQL statements. \n\nSQLAlchemy allows developers to create and ship enterprise-grade, production-ready Magento 2 applications easily and lets developers focus on business logic.\n\nSQLAlchemy is the Python SQL toolkit and Object Relational Mapper that gives application developers the full power and flexibility of SQL.\n\nIt provides a full suite of well-known enterprise-level persistence patterns, designed for efficient and high-performing database access, adapted into a simple and Pythonic domain language.\n\n# Models Structure \n\nPython abstraction over magento database has multiple Models per file vs Magento one file per Class \n\nPython is not exclusively class-based - the natural unit of code decomposition in Python is the module. Modules are just as likely to contain functions (which are first-class objects in Python) as classes. In PHP Magento, the unit of decomposition is the class. PyGento hes several models per file. each model represent DB table. One PyGento model file contains all the classes for e-Commerce function (Catalog, Sales, Customer, Quote, Inventory).\n\nPython is much more expressive than Magento, and if you restrict yourself to one class per file (which Python does not prevent you from doing) you will end up with lots of very small files - more to keep track of with very little benefit.\n\n# Database Connection \n\n```\nfrom sqlalchemy import create_engine\nengine = create_engine('mysql+pymysql://root:******@127.0.0.1/magento2')\nengine.connect()\n```\n\nTo make it simple, we configure it to JSON and use it, and read config.json or YML from the original config\n\n```\nphp -r '$x = include(\"app/etc/env.php\"); echo json_encode($x);' \u003e config.json\n```\n\n# Load Magento Model \n\n```\nfrom models.catalog import CatalogProductEntity as Product\n\nproducts = db.query(Product).all()\n\nfor product in products:\n    print (\"Product:\", product.__dict__) \n    print (\"Product Sku:\", product.sku) \n```\n## Magento/Adobe Commerce edition PyGento(Pythone) Support \nIf you have any issues or requires Magento Enterprise (Adobe Commerce/MSI) Version package, please, create a ticket or drop me email at: yegorshytikov@gmail.com\n\n# Tables relations \n\n## Many To One\nMany to one places a foreign key in the parent table referencing the child. relationship() is declared on the parent, where a new scalar-holding attribute will be created:\n```\nclass Parent(Base):\n    __tablename__ = 'parent'\n    id = Column(Integer, primary_key=True)\n    child_id = Column(Integer, ForeignKey('child.id'))\n    child = relationship(\"Child\")\n\nclass Child(Base):\n    __tablename__ = 'child'\n    id = Column(Integer, primary_key=True)\n```\nBidirectional behavior is achieved by adding a second relationship() and applying the relationship.back_populates parameter in both directions:\n\n```\n    __tablename__ = 'parent'\n    id = Column(Integer, primary_key=True)\n    child_id = Column(Integer, ForeignKey('child.id'))\n    child = relationship(\"Child\", back_populates=\"parents\")\n\nclass Child(Base):\n    __tablename__ = 'child'\n    id = Column(Integer, primary_key=True)\n    parents = relationship(\"Parent\", back_populates=\"child\")\n```\nAlternatively, the relationship.backref parameter may be applied to a single relationship(), such as Parent.child:\n```\nclass Parent(Base):\n    __tablename__ = 'parent'\n    id = Column(Integer, primary_key=True)\n    child_id = Column(Integer, ForeignKey('child.id'))\n    child = relationship(\"Child\", backref=\"parents\")\n```\n\n## Selectin Relations Load\nThe most useful loader in modern SQLAlchemy is the selectinload() loader option. This option solves the most common form of the “N plus one” problem which is that of a set of objects that refer to related collections. selectinload() will ensure that a particular collection for a full series of objects are loaded up front using a single query. It does this using a SELECT form that in most cases can be emitted against the related table alone, without the introduction of JOINs or subqueries, and only queries for those parent objects for which the collection isn’t already loaded. Below we illustrate selectinload() by loading all of the User objects and all of their related Address objects; while we invoke Session.execute() only once, given a select() construct, when the database is accessed, there are in fact two SELECT statements emitted, the second one being to fetch the related Address objects:\n\n```\nfrom sqlalchemy.orm import selectinload\nstmt = (\n  select(User).options(selectinload(User.addresses)).order_by(User.id)\n```\n\n# Async engine \nInitialize the new SQLAlchemy engine with create_async_engine() and create an async session maker by passing it the new AsyncSession class:\n```\nfrom sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy.ext.asyncio import AsyncSession\nfrom sqlalchemy.ext.asyncio import create_async_engine\nfrom sqlalchemy.orm import sessionmaker\n\n\nDATABASE_URL = \"postgresql+asyncpg://postgres:postgres@localhost/asyncalchemy\"\n\n\nengine = create_async_engine(DATABASE_URL, echo=True)\nBase = declarative_base()\nasync_session = sessionmaker(\n    engine, class_=AsyncSession, expire_on_commit=False\n)\n```\n\n# Performace\nAccording to the performace test, PyGento returns 1-20 order data in 1ms when Magento requires 200+ ms\nReturn 100 products with all data: Execution Time 0.07084512710571289 seconds in the debug mode and 0.05914497375488281 seconds in production mode\nArray Generate and Json Execution Time 0.008681297302246094 seconds\n```\nSelect Execution Time 0.05763673782348633 seconds\nTransponder Execution Time 0.0041141510009765625 seconds\nJson Execution Time 0.004602909088134766 seconds\nRequest Execution Time 0.0689239501953125 seconds\n```\nfor 10 product this results is:\n```\nSelect Execution Time 0.013299703598022461 seconds\nTransponder Execution Time 0.0005435943603515625 seconds\nJson Execution Time 0.0006403923034667969 seconds\nRequest Execution Time 0.016859769821166992 seconds\n```\nFor 1000 products result is: \n```\nSelect Execution Time 0.8228793144226074 seconds\nTransponder Execution Time 0.049771785736083984 seconds\nJson Execution Time 0.051209449768066406 seconds\nRequest Execution Time 0.9310669898986816 seconds\n```\n\nIn the future, these results can be improved using Async SQL requests and proper NoSQL product indexer...\n\n# Debug \n```\nengine = create_engine('mysql+pymysql://root:******@127.0.0.1/magento2', echo=True)\n```\nIf True, the Engine will log all statements and a repr() of their parameter lists to the default log handler, which defaults to sys.stdout for output. If set to the string \"debug,\" result rows will also be printed to the standard output.\n\n# \"Introduction to SQLAlchemy 2020 (Tutorial)\" by: Mike Bayer\n\nhttps://www.youtube.com/watch?v=sO7FFPNvX2s\n\nIn this tutorial, we present a \"from the ground up\" tour of SQLAlchemy, what\nthe general idea of it is how it's organized and what it looks like to use\nit.   This is the latest version of the \"classic\" SQLAlchemy tutorial  which\nhas been presented on many occasions since 2008, reworked for the current\nrecommended SQLAlchemy usage patterns with an emphasis on previewing the upcoming 1.4 and 2.0 releases of SQLAlchemy, which are poised to make major changes to many of SQLAlchemy's central paradigms and capabilities.\nSQLAlchemy is presented in terms of a four-layered model, which include \"Engine and Connection Basics\", \"Table Metadata\", \"SQL Expression Language\", and \"ORM Usage\" which is broken into two sections and API use is presented in terms of a console runner application which participants can install locally and follow along.  The tutorial will also present some of the newest in-development features of SQLAlchemy 1.4 which have only just merged.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgenaker%2Fpygento","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgenaker%2Fpygento","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgenaker%2Fpygento/lists"}