Just an aside: I discovered the sqlacodegen tool which will create the sqlalchemy class definitions automatically. I ran it against the civicrm mysql db and it worked. The definitions comprise 5881 lines (428KB). Fortunately I don't need much of it for my purposes.
On Tuesday, August 20, 2019 at 6:15:46 PM UTC-4, Ira Fuchs wrote: > > I think I may have all the definitions: > > class Contact(Base): > __tablename__ = "civicrm_contact" > id = Column(Integer, primary_key=True) > last_name = Column(String(20), nullable=False) > first_name = Column(String(20), nullable=False) > class Contribution(Base): > __tablename__ = "civicrm_contribution" > id = Column(Integer, primary_key=True) > contact_id = Column(Integer, nullable=False) > receive_date = Column(DateTime,nullable=False) > total_amount = Column(DECIMAL(precision=20,scale=2), nullable=False) > class Address(Base): > __tablename__ = "civicrm_address" > id = Column(Integer, primary_key=True) > contact_id = Column(Integer, nullable=False) > street_address = Column(String(96), nullable=False) > city = Column(String(64), nullable=False) > postalcode = Column(String(64), nullable=False) > country_id = Column(Integer, nullable=False) > class Country(Base): > __tablename__ = "civicrm_country" > id = Column(Integer, primary_key=True) > name = Column(String(64)) > class State(Base): > __tablename__ = "civicrm_state_province" > id = Column(Integer, primary_key=True) > name = Column(String(64), nullable=False) > abbreviation = Column(String(4), nullable=False) > country_id = Column(Integer, nullable=False) > class Entity_Tag(Base): > __tablename__ = "civicrm_entity_tag" > id = Column(Integer, primary_key=True) > entity_id = Column(Integer, nullable=False) > tag_id = Column(Integer, nullable=False) > > Now, how to create the equivalent SQL query? I presume that this > front-end overhead will pay back when I write more interesting scripts that > use data from Civicrm. If this works then I can map the remainder of the > (many) tables. > > On Tuesday, August 20, 2019 at 5:15:36 PM UTC-4, Ira Fuchs wrote: >> >> OK, fixed the case: >> >> class Contact(Base): >> __tablename__ = "civicrm_contact" >> id = Column(Integer, primary_key=True) >> last_name = Column(String(20), nullable=False) >> first_name = Column(String(20), nullable=False) >> class Contribution(Base): >> __tablename__ = "civicrm_contribution" >> id = Column(Integer, primary_key=True) >> contact_id = Column(Integer, nullable=False) >> receive_date = Column(DateTime,nullable=False) >> total_amount = Column(DECIMAL(precision=20,scale=2), nullable=False) >> >> On Tuesday, August 20, 2019 at 3:59:55 PM UTC-4, Ira Fuchs wrote: >>> >>> OK, I made some progress (see screenshot). I don't need the full model >>> to be represented as I will not need many of the columns in each of the >>> tables. If I could flesh this out enough so that I can do the query posted >>> above I can probably use that as a template to move forward. >>> >>> On Monday, August 19, 2019 at 7:11:59 AM UTC-4, Peter Schutt wrote: >>>> >>>> Cool, how about we walk through creating a model for your schema as an >>>> example. As we go I can point you to the relevant sections of the >>>> tutorials/docs as they are great and will explain the details much better >>>> than I can, and I'll try to address any questions you have along the way. >>>> >>>> The first thing you need is your Base class, all of your ORM models >>>> will inherit from this: >>>> >>>> from sqlalchemy.ext.declarative import declarative_base >>>> >>>> Base = declarative_base() >>>> >>>> >>>> Your models need to inherit from Base, need a __tablename__ class >>>> attribute and at least a primary key column. For example, a class to >>>> represent your "db_contact" table might look like this: >>>> >>>> from sqlalchemy import Column, Integer, String >>>> >>>> class Contact(Base): >>>> >>>> __tablename__ = "db_contact" >>>> >>>> id = Column(Integer, primary_key=True) >>>> last_name = Column(String(20), nullable=False) >>>> first_name = Column(String(20), nullable=False) >>>> >>>> Some things to note this far along: >>>> >>>> - In this example, the name of the Column in the database is >>>> inferred from the name of the class attribute that the Column is >>>> assigned >>>> to. >>>> - Column constructors take arguments that define specifics of how >>>> the column is defined in the database. E.g. `primary_key=True`, >>>> `nullable=False`. By declaring a single integer column as primary key, >>>> it >>>> will automatically be specified as autoincrement in the schema, as well >>>> as >>>> the primary key. Setting nullable=False on other columns declares that >>>> a >>>> NOT NULL constraint should be set on those columns. >>>> - As you are using MySQL, String types (which represent VARCHAR >>>> type in the database) require a length. If you were creating models for >>>> other backends such as SQLite or postgres, then that isn't required. >>>> >>>> Nothing that I've covered here isn't covered in the early stages of the >>>> ORM >>>> Tutorial >>>> <https://docs.sqlalchemy.org/en/13/orm/tutorial.html#declare-a-mapping>. >>>> Also, you can read the Column API >>>> <https://docs.sqlalchemy.org/en/13/core/metadata.html#sqlalchemy.schema.Column> >>>> to >>>> get a feel for the arguments that you can pass to Column in order to >>>> define >>>> your schema. >>>> >>>> One more important element is the Foreign Key. I'll use your >>>> "db_entity_tag" table to give you an example of that: >>>> >>>> from sqlalchemy import ForeignKey >>>> >>>> class EntityTag(Base): >>>> >>>> __tablename__ = "db_entity_tag" >>>> >>>> id = Column(Integer, primary_key=True) >>>> entity_id = Column( >>>> Integer, >>>> ForeignKey('db_contact.id', ondelete="CASCADE"), >>>> nullable=False, >>>> ) >>>> >>>> Pass the name of the related column to the ForeignKey object (note that >>>> this isn't "Class.attributename", it is "tablename.columnname") and pass >>>> the ForeignKey object as a positional argument to the Column constructor >>>> _after_ the column type argument. ForeignKey api is documented here >>>> <https://docs.sqlalchemy.org/en/13/core/constraints.html#sqlalchemy.schema.ForeignKey> >>>> and >>>> touched on in the orm tutorial here >>>> <https://docs.sqlalchemy.org/en/13/orm/tutorial.html#building-a-relationship> >>>> . >>>> >>>> Have a go at filling in the columns that I've missed in those models >>>> above and defining the rest of the tables in your schema and once you get >>>> that done we can move on. Happy to try to answer any questions you might >>>> have along the way. >>>> >>>> >>>> On Monday, 19 August 2019 12:36:21 UTC+10, Ira Fuchs wrote: >>>>> >>>>> Thanks for your reply and offer to help. I am able to create an Engine >>>>> and connect to the MySQL db. I can execute simple sql queries although I >>>>> wasn't able to get the query I posted to work due to a syntax error >>>>> (probably having to do with the quotes). I have not mapped any tables to >>>>> classes. >>>>> >>>>> On Sunday, August 18, 2019 at 8:54:57 PM UTC-4, Peter Schutt wrote: >>>>>> >>>>>> Hi Ira, I'd be happy to help you find your feet with the SQLAlchemy >>>>>> ORM. >>>>>> >>>>>> In general when creating an application that uses the SQLAlchemy ORM, >>>>>> you would start with an Engine (for connecting to the db), a declarative >>>>>> base class (maps db table to python class) and a Session instance (for >>>>>> using a connection to issue queries). Do you have any familiarity with >>>>>> those concepts? >>>>>> >>>>>> >>>>>> On Monday, 19 August 2019 02:34:05 UTC+10, Ira Fuchs wrote: >>>>>>> >>>>>>> I am new to sqlalchemy and I would like to begin using it to create >>>>>>> scripts with some sql queries that I have been using but need to change >>>>>>> from time to time. It would help a lot if someone could translate one >>>>>>> of >>>>>>> these queries to python sqlalchemy using an ORM (not simply executing >>>>>>> the >>>>>>> query as is) so that I could use this as a template for other queries, >>>>>>> or >>>>>>> at least learn from it. >>>>>>> >>>>>>> One of my queries looks like this: >>>>>>> >>>>>>> SELECT DISTINCT last_name, first_name, street_address, city, a.name, >>>>>>> postal_code, f.name as country FROM db_contact c, db_entity_tag d , >>>>>>> db_address e, db_state_province a, db_country f WHERE c.id = >>>>>>> d.entity_id and tag_id = 6 and c.id = e.contact_id AND >>>>>>> state_province_id = a.id and e.country_id = f.id and display_name >>>>>>> not in ( SELECT display_name FROM db_contribution, db_contact c, >>>>>>> db_entity_tag d WHERE receive_date > '2005-07-01' and contact_id = >>>>>>> c.id and c.id = entity_id and tag_id = 6 ) >>>>>>> >>>>>>> Thanks for any help. >>>>>>> >>>>>>> -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/07ef71e8-3d81-456b-b006-c1fb0c0603e7%40googlegroups.com.