6 Stimmen

sqlalchemy Verwendung von Vererbung in Postgres

In einem Versuch, Sqlalchemy (und Python) zu lernen, versuche ich, ein bereits vorhandenes Projekt zu duplizieren, aber ich habe Schwierigkeiten, Sqlalchemy und Vererbung mit Postgres herauszufinden.

Hier ist ein Beispiel dafür, was unsere Postgres-Datenbank tut (natürlich ist dies vereinfacht):

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);

Und dann würden die Einfügungen mit einem Trigger erfolgen, so dass sie ordnungsgemäß in die untergeordneten Datenbanken eingefügt werden. So etwas wie:

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;

zusammenfassend habe ich eine übergeordnete tabelle mit einem fremdschlüssel zu einer anderen tabelle. dann habe ich 2 untergeordnete tabellen, die es gibt, und die einfügungen erfolgen auf der Grundlage eines bestimmten Werts. in meinem Beispiel oben, wenn file_entry_system_name 'ops' ist, dann geht die Zeile in die Tabelle ops_file_entry; 'eng' geht in die Tabelle eng_file_entry_table. Wir haben in unserer Produktionsumgebung Hunderte von untergeordneten Tabellen, und in Anbetracht der Datenmenge beschleunigt das die Dinge wirklich, daher möchte ich diese Struktur beibehalten. Ich kann die übergeordnete Tabelle abfragen, und solange ich ihr den richtigen "system_name" gebe, weiß sie sofort, in welche untergeordnete Tabelle sie schauen muss.

Mein Wunsch ist es, dies mit Sqlalchemy zu emulieren, aber ich kann keine Beispiele finden, die in dieses Detail gehen. Ich schaue auf die Sql, die von Sqlalchemy von Beispielen generiert wird, und ich kann sagen, dass es nicht etwas Ähnliches wie diese auf der Datenbankseite tut.

Das Beste, was mir einfällt, ist so etwas wie:

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'}

Was übersehe ich letztendlich? Wie sage ich Sqlalchemy, dass alles, was in FileEntry mit dem Systemnamen "ops" eingefügt wird, in die Tabelle "ops_file_entry" übertragen wird? Liege ich da falsch?

Ein Einblick in das, was ich tun sollte, wäre fantastisch.

1voto

sayap Punkte 5841

Sie erstellen einfach eine neue Instanz von ops_file_entry (sollte das nicht heißen OpsFileEntry ?), fügen Sie sie in die Sitzung ein, und beim Flush wird eine Zeile in die Tabelle file_entry sowie die Tabelle ops_file_entry .

Sie müssen nicht die file_entry_system_name Attribut noch den Auslöser.

0voto

bostonou Punkte 1174

Ich kenne weder Python noch Sqlalchemy, aber ich dachte mir, ich probiere es mal aus, um der alten Zeiten willen ;)

Haben Sie versucht, einen eigenen Auslöser auf der Anwendungsebene einzurichten? So etwas könnte funktionieren:

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)

Ich bin mir nicht sicher, aber ich glaube target (oder vielleicht mapper ) sollte die einzufügenden Daten enthalten.

Ereignisse (insb. after_create) y Mapper wird wahrscheinlich hilfreich sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X