mardi 14 juin 2016

SQLAlchemy Automap backref errors

I am new to SQLAlchemy (ORMs in generally) and I am trying to move an existing application on to SQLAlchemy so that we can shift some of the code complexity from the currently existing (and tedious to update) queries, to Python. Unfortunately, I haven't been able to experiment that much because I am getting errors immediately after database reflection, and I cannot find a solution. Below is an approximately minimal example of what I am trying to do and the stack trace.

Existing postgres table:

dev=> d+ gmt_file
                                        Table "public.gmt_file"
         Column          |           Type           | Modifiers | Storage  | Stats target | Description 
-------------------------+--------------------------+-----------+----------+--------------+-------------
 file_id                 | integer                  | not null  | plain    |              | 
 file_name               | character varying(255)   |           | extended |              | 
 mime_type               | character varying(255)   | not null  | extended |              | 
 file                    | bytea                    | not null  | extended |              | 
 created                 | timestamp with time zone | not null  | plain    |              | 
 created_by              | integer                  | not null  | plain    |              | 
 company_id              | integer                  | not null  | plain    |              | 
 deleted                 | timestamp with time zone |           | plain    |              | 
 deleted_by              | integer                  |           | plain    |              | 
 status                  | character varying(1)     | not null  | extended |              | 
 parent_file_id          | integer                  |           | plain    |              | 

Indexes:
    "gmt_file_pk" PRIMARY KEY, btree (file_id)
    "gmt_file_company_idx" btree (company_id)
Foreign-key constraints:
    "gmt_file_company_fk" FOREIGN KEY (company_id) REFERENCES gmt_company(company_id)
    "gmt_file_deleted_user_fk" FOREIGN KEY (deleted_by) REFERENCES cmn_user(user_id)
    "gmt_file_parent_file_id_fk" FOREIGN KEY (parent_file_id) REFERENCES gmt_file(file_id)
    "gmt_file_status_fk" FOREIGN KEY (status) REFERENCES gmt_file_status_code(status)
    "gmt_file_user_fk" FOREIGN KEY (created_by) REFERENCES cmn_user(user_id)
Referenced by:
    TABLE "gmt_file" CONSTRAINT "gmt_file_parent_file_id_fk" FOREIGN KEY (parent_file_id) REFERENCES gmt_file(file_id)
    TABLE "gmt_style" CONSTRAINT "gmt_style_file_fk" FOREIGN KEY (file_id) REFERENCES gmt_file(file_id)

SQLAlchemy Application (minimal example):

from sqlalchemy import create_engine
from sqlalchemy.orm import Session,Mapper
from sqlalchemy.ext.automap import automap_base

engine = create_engine('postgresql://user:pass@localhost:5432/dev')
Base = automap_base()
Base.prepare(engine, reflect=True)
session = Session(engine,autocommit=True)

session.query(Base.classes.gmt_file).all()

Stack Trace:

---------------------------------------------------------------------------
ArgumentError                             Traceback (most recent call last)
<ipython-input-5-e0284415685d> in <module>()
----> 1 session.query(str_store_defn).all()

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/session.py in query(self, *entities, **kwargs)
   1258         :class:`.Session`."""
   1259 
-> 1260         return self._query_cls(entities, self, **kwargs)
   1261 
   1262     @property

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/query.py in __init__(self, entities, session)
    108         self.session = session
    109         self._polymorphic_adapters = {}
--> 110         self._set_entities(entities)
    111 
    112     def _set_entities(self, entities, entity_wrapper=None):

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/query.py in _set_entities(self, entities, entity_wrapper)
    118             entity_wrapper(self, ent)
    119 
--> 120         self._set_entity_selectables(self._entities)
    121 
    122     def _set_entity_selectables(self, entities):

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/query.py in _set_entity_selectables(self, entities)
    148                         aliased_adapter
    149                     )
--> 150                 ent.setup_entity(*d[entity])
    151 
    152     def _mapper_loads_polymorphically_with(self, mapper, adapter):

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/query.py in setup_entity(self, ext_info, aliased_adapter)
   3444         self.selectable = ext_info.selectable
   3445         self.is_aliased_class = ext_info.is_aliased_class
-> 3446         self._with_polymorphic = ext_info.with_polymorphic_mappers
   3447         self._polymorphic_discriminator = 
   3448             ext_info.polymorphic_on

/usr/local/lib/python3.5/site-packages/sqlalchemy/util/langhelpers.py in __get__(self, obj, cls)
    752         if obj is None:
    753             return self
--> 754         obj.__dict__[self.__name__] = result = self.fget(obj)
    755         return result
    756 

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/mapper.py in _with_polymorphic_mappers(self)
   1891     def _with_polymorphic_mappers(self):
   1892         if Mapper._new_mappers:
-> 1893             configure_mappers()
   1894         if not self.with_polymorphic:
   1895             return []

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/mapper.py in configure_mappers()
   2768                 if not mapper.configured:
   2769                     try:
-> 2770                         mapper._post_configure_properties()
   2771                         mapper._expire_memoizations()
   2772                         mapper.dispatch.mapper_configured(

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/mapper.py in _post_configure_properties(self)
   1708 
   1709             if prop.parent is self and not prop._configure_started:
-> 1710                 prop.init()
   1711 
   1712             if prop._configure_finished:

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/interfaces.py in init(self)
    181         """
    182         self._configure_started = True
--> 183         self.do_init()
    184         self._configure_finished = True
    185 

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/relationships.py in do_init(self)
   1630         self._check_cascade_settings(self._cascade)
   1631         self._post_init()
-> 1632         self._generate_backref()
   1633         self._join_condition._warn_for_conflicting_sync_targets()
   1634         super(RelationshipProperty, self).do_init()

/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/relationships.py in _generate_backref(self)
   1821                         "'%s' on relationship '%s': property of that "
   1822                         "name exists on mapper '%s'" %
-> 1823                         (backref_key, self, m))
   1824 
   1825             # determine primaryjoin/secondaryjoin for the

ArgumentError: Error creating backref 'gmt_file' on relationship 'gmt_file.gmt_file': property of that name exists on mapper 'Mapper|gmt_file|gmt_file'

I have tried multiple ways of handling this error, including creating custom naming functions (name_for_scalar_relationship(), and name_for_collection_relationship()), to no avail. The ultimate goal would be to reflect the db in an automated way, and not have to write custom name mappings for the hundreds of tables that exist currently, but I am at a loss for what to do. Any help is appreciated.

Thank you

Aucun commentaire:

Enregistrer un commentaire