6

w próbie nauczenia się sqlalchemy (i python), próbuję skopiować istniejący projekt, ale mam problem z wykryciem sqlalchemy i dziedziczenia z postgres.sqlalchemy wykorzystanie dziedziczenia w postgresie

tutaj jest przykładem tego, co robi nasza baza danych PostgreSQL (oczywiście, jest to uproszczony):

CREATE TABLE system (system_id SERIAL PRIMARY KEY, 
        system_name VARCHAR(24) NOT NULL); 
CREATE TABLE file_entry(file_entry_id SERIAL, 
         file_entry_msg VARCHAR(256) NOT NULL, 
         file_entry_system_name VARCHAR(24) REFERENCES system(system_name) NOT NULL); 
CREATE TABLE ops_file_entry(CONSTRAINT ops_file_entry_id_pkey PRIMARY KEY (file_entry_id), 
    CONSTRAINT ops_system_name_check CHECK ((file_entry_system_name = 'ops'::bpchar))) INHERITS (file_entry); 
CREATE TABLE eng_file_entry(CONSTRAINT eng_file_entry_id_pkey PRIMARY KEY (file_entry_id), 
    CONSTRAINT eng_system_name_check CHECK ((file_entry_system_name = 'eng'::bpchar)) INHERITS (file_entry); 
CREATE INDEX ops_file_entry_index ON ops_file_entry USING btree (file_entry_system_id); 
CREATE INDEX eng_file_entry_index ON eng_file_entry USING btree (file_entry_system_id); 

A potem wkładki byłaby zrobiona z wyzwalaczem, tak aby były one prawidłowo umieszczona w bazach danych potomnych . Coś jak:

CREATE FUNCTION file_entry_insert_trigger() RETURNS "trigger" 
    AS $$ 
DECLARE 
BEGIN 
    IF NEW.file_entry_system_name = 'eng' THEN 
     INSERT INTO eng_file_entry(file_entry_id, file_entry_msg, file_entry_type, file_entry_system_name) VALUES (NEW.file_entry_id, NEW.file_entry_msg, NEW.file_entry_type, NEW.file_entry_system_name); 
    ELSEIF NEW.file_entry_system_name = 'ops' THEN 
     INSERT INTO ops_file_entry(file_entry_id, file_entry_msg, file_entry_type, file_entry_system_name) VALUES (NEW.file_entry_id, NEW.file_entry_msg, NEW.file_entry_type, NEW.file_entry_system_name); 
    END IF; 
    RETURN NULL; 
END; 
$$ LANGUAGE plpgsql; 

w podsumowaniu, mam tabelę nadrzędną z kluczem obcym do innej tabeli. następnie mam 2 tabele potomne, które istnieją, a wstawki są wykonywane na podstawie danej wartości. w powyższym przykładzie, jeśli file_entry_system_name to "ops", to wiersz przechodzi do tabeli ops_file_entry; "eng" przechodzi do pliku eng_file_entry_table. mamy setki stołów dla dzieci w naszym środowisku produkcyjnym, a biorąc pod uwagę ilość danych, to naprawdę przyspiesza to, więc chciałbym zachować tę samą strukturę. Mogę zapytać rodzica i tak długo, jak daję mu prawo "nazwa_systemu", od razu wie, do którego tabeli podrzędnej się zajrzy.

moim pragnieniem jest naśladować to za pomocą sqlalchemy, ale nie mogę znaleźć żadnych przykładów, które pasują do tak wielu szczegółów. Patrzę na sql generowane przez sqlalchemy przez przykłady i mogę powiedzieć, że nie robi nic podobnego do tego po stronie bazy danych.

najlepszy mogę wymyślić coś takiego jak:

class System(_Base): 
    __tablename__ = 'system' 
    system_id = Column(Integer, Sequence('system_id_seq'), primary_key = True) 
    system_name = Column(String(24), nullable=False) 
    def __init(self, name) 
     self.system_name = name 
class FileEntry(_Base): 
    __tablename__ = 'file_entry' 
    file_entry_id = Column(Integer, Sequence('file_entry_id_seq'), primary_key=True) 
    file_entry_msg = Column(String(256), nullable=False) 
    file_entry_system_name = Column(String(24), nullable=False, ForeignKey('system.system_name')) 
    __mapper_args__ = {'polymorphic_on': file_entry_system_name} 
    def __init__(self, msg, name) 
     self.file_entry_msg = msg 
     self.file_entry_system_name = name 
class ops_file_entry(FileEntry): 
    __tablename__ = 'ops_file_entry' 
    ops_file_entry_id = Column(None, ForeignKey('file_entry.file_entry_id'), primary_key=True) 
    __mapper_args__ = {'polymorphic_identity': 'ops_file_entry'} 

w końcu, co mi brakuje? jak powiedzieć sqlalchemy, aby powiązać wszystko, co jest wstawiane do FileEntry z nazwą systemu "ops", aby przejść do tabeli "ops_file_entry"? czy moje rozumienie jest daleko?

Wgląd w to, co powinienem zrobić, byłby niesamowity.

+0

http://www.sqlalchemy.org/trac/wiki/UsageRecipes/PostgreSQLInheritance – jasonmclose

Odpowiedz

0

Naprawdę nie znam Pythona ani SQlalchemy, ale doszedłem do wniosku, że dałbym temu zastrzyk w dawnych czasach. ;)

Czy próbowałeś już ustawić własny wyzwalacz na poziomie aplikacji? Coś jak to może działać:

from sqlalchemy import event, orm 

def my_after_insert_listener(mapper, connection, target): 
    # set up your constraints to store the data as you want 
    if target.file_entry_system_name = 'eng' 
     # do your child table insert 
   elseif target.file_entry_system_name = 'ops' 
     # do your child table insert 
    #… 

mapped_file_entry_class = orm.mapper(FileEntry, 'file_entry') 
# associate the listener function with FileEntry, 
# to execute during the "after_insert" hook 
event.listen(mapped_file_entry_class, 'after_insert', my_after_insert_listener) 

Nie jestem pewien, ale myślę target (albo mapper) powinna zawierać dane są wstawiane. Pomocne będzie prawdopodobnie

Events (esp. after_create) i mapper.

+0

Próbuję uciec od tworzenia wyzwalacza. powinien istnieć sposób informowania sqlalchemy o sposobie działania dziedziczek oraz o sposobie obsługi ograniczenia, do którego tabeli podrzędnej należy wstawić. wszystko powinno być możliwe w deklaratywnej metodzie tworzenia tabel. Dziękuję za odpowiedź. – jasonmclose

1

Wystarczy utworzyć nową instancję ops_file_entry (nie powinno to być OpsFileEntry?), Dodaj go do sesji, a po spłukiwania, jeden wiersz zostanie wstawiony do tabeli file_entry jak również tabeli ops_file_entry.

Nie trzeba ustawiać atrybutu file_entry_system_name ani wyzwalacza.