SQLAlchemy-versiebeheer geeft om de importvolgorde van klassen

| | | | | | | | | |

Ik volgde de handleiding hier:

http ://www.sqlalchemy.org/docs/orm/examples.html?highlight=versioning#versioned-objects

en zijn een probleem tegengekomen. Ik heb mijn relaties als volgt gedefinieerd:

generic_ticker = relation("MyClass", backref=backref("stuffs")) 

met strings zodat het niet Het maakt me niet uit wat de importvolgorde van mijn modelmodules is. Normaal gesproken werkt dit allemaal prima, maar als ik de versiebeheermeta gebruik, krijg ik de volgende foutmelding:

sqlalchemy.exc.InvalidRequestError: Bij het initialiseren van mapper Mapper|MyClass|stuffs, expressie "Trader" kan geen naam vinden ("naam "MyClass" is niet gedefinieerd"). Als dit een klassenaam is, overweeg dan om deze relatie() aan de klasse toe te voegen nadat beide afhankelijke klassen zijn gedefinieerd .

Ik heb de fout gevonden in:

 Bestand "/home/nick/workspace/gm3/gm3/lib/history_meta.py", regel 90, in __init__ mapper = class_mapper(cls) Bestand "/home/nick/venv/tg2env/lib/python2.6/site-packages/sqlalchemy/orm/util.py", regel 622, in class_mapper mapper = mapper.compile () 

class VersionedMeta(DeclarativeMeta): def __init__(cls, cl assname, bases, dict_): DeclarativeMeta.__init__(cls, classname, bases, dict_) probeer: mapper = class_mapper(cls) _history_mapper(mapper) behalve UnmappedClassError: pass 

Ik heb het probleem opgelost door de try: behalve dingen in een lambda te plaatsen en ze allemaal uit te voeren nadat alle importen zijn gebeurd. Dit werkt, maar lijkt een beetje onzin. Enig idee hoe dit op te lossen is een betere manier?

Bedankt!

Update

Het probleem gaat eigenlijk niet over de importorder. Het versiebeheervoorbeeld is zo ontworpen dat mapper een compilatie in costructuur van elke klasse met versiebeheer vereist. En compilatie mislukt wanneer gerelateerde klassen nog niet zijn gedefinieerd. In het geval van circulaire relaties is er geen manier om het te laten werken door de definitievolgorde van toegewezen klassen te veranderen.

Update 2

Zoals de bovenstaande update aangeeft ( Ik wist niet dat je de berichten van andere mensen hier kon bewerken :)) dit is waarschijnlijk te wijten aan kringverwijzingen. In dat geval kan iemand mijn hack nuttig vinden (ik gebruik hem met turbogears) (Vervang VersionedMeta en voeg create_mappers global toe aan history_meta)

create_mappers = [] class VersionedMeta(DeclarativeMeta) : def __init__(cls, classname, bases, dict_): DeclarativeMeta.__init__(cls, classname, bases, dict_) #Ik heb deze code toegevoegd omdat deze crashte, anders def make_mapper(): try: mapper = class_mapper(cls) _history_mapper (mapper) behalve UnmappedClassError: pass create_mappers.append(lambda: make_mapper()) 

Dan kun je zoiets als het volgende doen in je modellen __init__.py

# Importeer uw modelmodules hier uit myproj.lib.history_meta import create_mappers uit myproj.model.misc import * from myproj.model.actor import * from myproj.model.stuff1 import * from myproj.model.instrument import * from myproj.model.stuff import * #setup the history [func() for func in create_mappers] 

Op die manier worden alleen de mappers gemaakt nadat alle klassen zijn gedefinieerd.

Update 3 Enigszins niet gerelateerd, maar in sommige omstandigheden kwam ik een dubbele primaire sleutelfout tegen (twee wijzigingen in hetzelfde object in één keer uitvoeren) . Mijn tijdelijke oplossing was om een nieuwe primaire sleutel voor automatisch verhogen toe te voegen. Natuurlijk kun je er niet meer dan 1 hebben met mysql, dus ik moest de primaire sleutel deprimeren die werd gebruikt om de geschiedenistabel te maken. Bekijk mijn algemene code (inclusief een hist_id en het wegwerken van de externe sleutelbeperking):

"""Gestolen van de officiële sqlalchemy recpies """ van sqlalchemy.ext.declarative import DeclarativeMeta van sqlalchemy.orm import mapper, class_mapper, attributen, object_mapper van sqlalchemy.orm.exc import UnmappedClassError, UnmappedColumnError uit sqlalchemy import Table, Column, ForeignKeyConstraint, Integer from sqlalchemy.orm.interfaces import SessionExtension uit sqlalchemy.orm.properties import RelationshipProperty uit sqlalchemy.types import DateTime import datetime uit sqlalchemy.orm.colsession import Table deftable : for fk in col.foreign_keys: if fk.references(table): return True return False def _history_mapper(local_mapper): cls = local_mapper.class_ # zet de vlag "active_history" # op op kolom toegewezen a ttributes zodat de oude versie # van de info altijd wordt geladen (momenteel wordt het ingesteld op alle attributen) voor prop in local_mapper.iterate_properties: getattr(local_mapper.class_, prop.key).impl.active_history = True super_mapper = local_mapper.inherits super_history_mapper = getattr(cls, "__history_mapper__", Geen) polymorphic_on = Geen super_fks = [] indien niet super_mapper of local_mapper.local_table is niet super_mapper.local_table: cols = [] voor kolom in local_mapper.local_table.c: indien kolom.naam == "version": continue col = column.copy() col.unique = False #don't dingen automatisch ophogen van de normale db als col.autoincrement: col.autoincrement = False #sqllite valt om met auto-incrementerende sleutels als we een samengestelde sleutel indien col.primary_key: col.primary_key = False indien super_mapper en col_references_table(column, super_mapper.local_table): super_fks.append((col.key, list(super_history_mapper.base_mapper.local_table.primary_key)[0])) cols. append(col) als kolom local_mapper.polymorphi is c_on: polymorphic_on = col #if super_mapper: # super_fks.append(("version", super_history_mapper.base_mapper.local_table.c.version)) cols.append(Column("hist_id", Integer, primary_key=True, autoincrement=True) ) cols.append(Column("version", Integer)) cols.append(Column("changed", DateTime, default=datetime.datetime.now)) if super_fks: cols.append(ForeignKeyConstraint(*zip(*super_fks) )) table = Table(local_mapper.local_table.name + "_history", local_mapper.local_table.metadata, *cols, mysql_engine="InnoDB") anders: # enkele tabelovererving. neem eventuele extra kolommen die # zijn toegevoegd en voeg ze toe aan de geschiedenistabel. voor kolom in local_mapper.local_table.c: if column.key niet in super_history_mapper.local_table.c: col = column.copy() super_history_mapper.local_table.append_column(col) table = Geen if super_history_mapper: bases = (super_history_mapper.class_,) anders: bases = local_mapper.base_mapper.class_.__bases__ versioned_cls = type.__new__(type, "%sHistory" % cls.__name__, bases, {}) m = mapper( versioned_cls, table, inherits=super_history_mapper, polymorphic_on=polymorphic_on, polymorphic =local_mapper.polymorphic_identity ) cls.__history_mapper__ = m indien niet super_history_mapper: cls.version = Column("version", Integer, default=1, nullable=False) create_mappers = [] class VersionedMeta(DeclarativeMeta): def __init__(cls, classname , bases, dict_): DeclarativeMeta.__init__(cls, classname, bases, dict_) #Ik heb deze code toegevoegd omdat deze crashte, anders def make_mapper(): try: mapper = class_mapper(cls) _history_mapper(mapper) behalve UnmappedClassError: pass create_mappers.append(lambda: make_mapper()) def versioned_objects(iter): voor obj in iter: if hasattr(obj, "__history_mapper__"): opbrengst obj def create_version(obj, session, delete = False): obj_mapper = object_mapper(obj) history_mapper = obj.__history_mapper__ history_cls = history_mapper.class_ obj_state = attributes.instance_state(obj) attr = {} obj_changed = False voor om, hm in zip(obj_mapper.iterate_to_root(), history_mapper.iterate_to_root()): indien hm.single: ga verder voor hist_col in hm .local_table.c: if hist_col.key == "versie" of hist_col.key == "gewijzigd" of hist_col.key == "hist_id": doorgaan obj_col = om.local_table.c[hist_col.key] # verkrijg de waarde van het # attribuut gebaseerd op de MapperProperty gerelateerd aan de # toegewezen kolom. hierdoor kunnen MapperProperties # worden gebruikt die een andere sleutelnaam hebben dan die van de toegewezen kolom. probeer: prop = obj_mapper.get_property_by_column(obj_col) behalve UnmappedColumnError: # in het geval van overerving van één tabel, kunnen er # kolommen op de toegewezen tabel zijn die alleen voor de subklasse zijn bedoeld. # de "niet-toegewezen" status van de subklassekolom op de # basisklasse is een kenmerk van de declaratieve module vanaf sqla 0.5.2. doorgaan # verlopen objectkenmerken en ook uitgestelde cols staan mogelijk niet in het # dict. forceer het om te laden, wat er ook gebeurt door getattr() te gebruiken. if prop.key niet in obj_state.dict: getattr(obj, prop.key) a, u, d = attributes.get_history(obj, prop.key) if d: attr[hist_col.key] = d[0] obj_changed = True elif u: attr[hist_col.key] = u[0] else: # als het attribuut geen waarde had. attr[hist_col.key] = a[0] obj_changed = True indien niet obj_changed: # niet gewijzigd, maar we hebben relaties. OK # controleer die ook voor prop in obj_mapper.iterate_properties: if isinstance(prop, RelationshipProperty) en attributes.get_history(obj, prop.key).has_changes(): obj_changed = True break indien niet obj_changed en niet verwijderd: return attr[" version"] = obj.version hist = history_cls() voor sleutel, waarde in attr.iteritems(): setattr(hist, sleutel, waarde) obj.version += 1 session.add(hist) klasse VersionedListener(SessionExtension): def before_flush(self, session, flush_context, instances): voor obj in versioned_objects(session.dirty): create_version(obj, session) voor obj in versioned_objects(session.deleted): create_version(obj, session, delete = True) 

Shop

Learn programming in R: courses

$

Best Python online courses for 2022

$

Best laptop for Fortnite

$

Best laptop for Excel

$

Best laptop for Solidworks

$

Best laptop for Roblox

$

Best computer for crypto mining

$

Best laptop for Sims 4

$

Latest questions

NUMPYNUMPY

psycopg2: insert multiple rows with one query

12 answers

NUMPYNUMPY

How to convert Nonetype to int or string?

12 answers

NUMPYNUMPY

How to specify multiple return types using type-hints

12 answers

NUMPYNUMPY

Javascript Error: IPython is not defined in JupyterLab

12 answers

News


Wiki

Python OpenCV | cv2.putText () method

numpy.arctan2 () in Python

Python | os.path.realpath () method

Python OpenCV | cv2.circle () method

Python OpenCV cv2.cvtColor () method

Python - Move item to the end of the list

time.perf_counter () function in Python

Check if one list is a subset of another in Python

Python os.path.join () method