2012-06-05 11 views
5

Byłem absolutnie dręczący mój mózg nad tym i nie mogę wydawać się wypracowywać jak obejść problem. Należy pamiętać, że mam wyciąć dużo dziedzinach niezwiązanych z moich modeliDziedziczenie + zagraniczne klucze

Jestem w środku kodowania moje modele SQL Alchemy, i napotkał następujący problem:

Ze względu na wielu systemach rozliczeniowych, za każdym z zupełnie innymi atrybutami, a ze względu na różne typy atrybutów subskrypcji (tj. nazwy użytkowników, lokalizacje węzłów itp.) musiałem zejść po polimorficznej drodze dziedziczenia.

class Subscription(Base): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(255)) 
    secret = db.Column(postgresql.BYTEA) 
    type = db.Column(SubscriptionType.db_type()) 
    status = db.Column(StatusType.db_type()) 
    subscription_id = db.Column(db.Integer) 

    __tablename__ = 'subscription' 
    __table_args__ = {'schema':'public'} 

    __mapper_args__ = {'polymorphic_on' : type} 

    def __repr__(self): 
     return '<Subscription: %r>' % self.id 

class Product1(Subscription): 
    __mapper_args__ = {'polymorphic_identity' : SubscriptionType.product1}  
    id = db.Column(db.Integer, db.ForeignKey('public.subscription.id'), 
     primary_key = True) 
    billing_system = db.Column(
     db.Integer, 
     db.ForeignKey('public.billing_system.id') 
    ) 

class BillingSystem(Base): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(255)) 
    type = db.Column(BillingSystemType.db_type()) 

    __tablename__ = 'billing_system' 
    __table_args__ = {'schema':'public'} 

    __mapper_args__ = {'polymorphic_on' : type} 

    def __repr__(self): 
     return '<Subscription: %r>' % self.id 

class BillingSystem1(BillingSystem): 
    __mapper_args__ = {'polymorphic_identity' : BillingSystemType.billingsystem1}  
    id = db.Column(db.Integer, db.ForeignKey('public.billing_system.id'), 
     primary_key = True) 
    billing_system = db.Column(
     db.Integer, 
     db.ForeignKey('public.billing_system.id') 
    ) 
    foo = db.Column(db.Integer) 
    bar = db.Column(db.Integer) 

class BillingSystem2(BillingSystem): 
    __mapper_args__ = {'polymorphic_identity' : BillingSystemType.billingsystem2}  
    id = db.Column(db.Integer, db.ForeignKey('public.billing_system.id'), 
     primary_key = True) 
    billing_system = db.Column(
     db.Integer, 
     db.ForeignKey('public.billing_system.id') 
    ) 
    bing = db.Column(db.Integer) 
    boo = db.Column(db.Integer) 


    __tablename__ = 'billing_system_product2' 
    __table_args__ = {'schema':'public'} 

Wszystko działa dobrze, z wyjątkiem jednej rzeczy.

Powiedzmy, że mogę uruchomić następujące:

>>> a = Product1() 
>>> b = BillingSystem.objects.get(1) 
>>> a.billing_system = b 
>>> session.add(a) 
>>> session.commit() 

będę następujący komunikat o błędzie.

sqlalchemy.exc.ProgrammingError: (ProgrammingError) can't adapt type 'BillingSystem1' 'INSERT INTO 

Rozumiem, co mówi, a próbowałem następujące.

>>> a.billing_system = b.id 

To tylko przechowuje identyfikator, a gdy próbuję retreive wiązany obiekt, to zamiast otrzymać całkowitą. To wymaga ode mnie dodatkowego zapytania. Spodziewałbym się, że to nie jest droga.

Próbowałem również dodawanie kluczy obcych dla wszystkich identyfikatorów systemu billingowego do Produkt1 model

class BillingSystem1(BillingSystem): 
    __mapper_args__ = {'polymorphic_identity' : BillingSystemType.billingsystem1}  
    id = db.Column(db.Integer, db.ForeignKey('public.billing_system.id'), 
     primary_key = True) 
    billing_system = db.Column(
     db.Integer, 
     db.ForeignKey('public.billing_system.id'), 
     db.ForeignKey('public.billing_system1.id'), 
     db.ForeignKey('public.billing_system2.id'), 
    ) 
    foo = db.Column(db.Integer) 
    bar = db.Column(db.Integer) 

To również nie działa w ogóle, a ja otrzymałem ten sam wyjątek ProgrammingError stwierdzający, że typ może dostosuj się.

Mam trawled instrukcję, a nie mogę znaleźć jak to zrobić, ale trzeba jakąś formę opcji magicznego do tego dopuścić:

>>> a = BillingSystem.query.get(1) 
>>> type(a) 
BillingSystem 

Zamiast:

>>> a = BillingSystem.query.get(1) 
>>> type(a) 
BillingSystem1 

Czy ktoś jest w stanie rzucić jakiekolwiek światło na to, w jaki sposób mogę wysłać zapytanie do mojego zestawu modeli polimorficznych o identyfikator i uzyskać tylko klasę modelu podstawowego?

Uważam, że rozwiąże to mój problem, nie jestem pewien, jak go rozwiązać.

Dzięki za poświęcenie czasu na przeczytanie tego, a ja naprawdę chciałbym dowiedzieć się, gdzie idę źle (zbyt długo czułem się tak długo, więc to nie pomaga).

Cheers, Rhys

+3

To prawdopodobnie nie będzie to odpowiedź super pomocne dla ciebie, ale wydaje się, że aby dowiedzieć się, czy mogę ci pomóc, będę musiał czytać Ogromna ilość twojego kodu i wymyśl małe szczegóły. Najlepszym sposobem uzyskania odpowiedzi na tej stronie jest podanie kodu w dół, aż stanie się niewiarygodnie prosty, ale nadal daje ten sam błąd. Następnie możesz zadać bardzo konkretne pytanie: "dlaczego linia 3 tych 4 linii kodu powoduje błąd?" Jako dodatkowy bonus zazwyczaj * rozwiązujesz * problem, kiedy przechodzisz przez ten proces. Powodzenia! –

+1

Trochę odpoczynku i twoja rada pomogły dużo! Dziękuję Ci :) –

Odpowiedz

1
class Subscription(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(255)) 
    secret = db.Column(postgresql.BYTEA) 
    type = db.Column(SubscriptionType.db_type()) 
    status = db.Column(StatusType.db_type()) 
    subscription_id = db.Column(db.Integer) 

    billing_system_id = db.Column(
     db.Integer, 
     db.ForeignKey('public.billing_system.id') 
    ) 
    billing_system = db.relationship('BillingSystem', backref='subscriptions') 

Więc co mam zrobić to:

1) przesunął Subscription.billing_system_id klucz obcy do bazy subskrypcji modelu 2) Dodane w subskrypcji.billing_system związku

Więc teraz robie to:

>>> o = BillingSystem.query.get(1) 
>>> a = Product1() 
>>> a.billing_system_id = o.id 

co skutkuje:

>>> a.billing_system.subscriptions 
[<cPanel Hosting Reseller: 2>] 
>>> a.billing_system_id 
2 

Więc chyba że robię coś złego tutaj, wydaje się działać. Po prostu nie mogę przekazać rzeczywistego obiektu BillingSystem, muszę ustawić ID. Nadal jest wymuszane referencyjnie, gdy model jest zapisany, więc nie widzę zbyt wielu problemów z nim.

Dzięki za pomoc :)