J'ai la configuration suivante:

class Attribute(object):
    a = Column(Integer)

class Thing(Base, Attribute):
    b = Column(Integer)

class Subthing(Thing):
    c = COlumn(Integer)

Cependant, Thing et Subthing auront le mixage d'attribut, ce qui signifie qu'ils auront tous les deux les colonnes spécifiées dans Attribute:

Thing: a | b
Subthing: a | c

Je veux seulement ces colonnes mixin présentes dans Thing et non Subthing:

Thing: a | b
Subthing: c

Est-ce possible ou devrai-je recourir à la création manuelle de colonnes et de méthodes au lieu d'utiliser un mixage pour chaque chose?

0
Jonathan Ong 6 oct. 2011 à 09:04

3 réponses

Meilleure réponse

Subthing obtient a du parent par définition de l'héritage. Si vous ne souhaitez pas ce comportement, Subthing ne peut pas hériter de cet objet. Une solution possible consiste à introduire une autre classe de base.

class Attribute(object):
    @declared_attr # the actual syntax on SQLAlchemy for doing mixins
    def a(cls):
       return Column(Integer)

class BaseThing(Base):
    pass

class Thing(BaseThing, Attribute):
    b = Column(Integer)

class Subthing(BaseThing):
    c = Column(Integer)

Ensuite, Subthing n'a que la colonne c, et Thing a a et b.

4
Michael Merickel 6 oct. 2011 à 15:15

Il s'agit d'une incohérence comportementale qui résulte du comportement de @declared_attr s'écartant lentement d'un contrat comportemental qui n'a été testé que par rapport au cas d'utilisation de la "copie de colonne". Le cas d'utilisation d'origine de la "colonne sur mixin" était de l'appliquer également à toutes les classes héritées, cependant @declared_attr, qui a été développé un peu plus tard, n'a pas adopté ce comportement, donc incohérent.

La modification de la "copie de colonne" pour ne prendre effet que pour la non-sous-classe est un changement de comportement incompatible en amont, comme c'est le cas pour la version 0.8 à venir. Il s'agit du ticket # 2565 (http://www.sqlalchemy.org/trac/ticket/2565) et est résolu dans r9baa197f2c67.

Tester:

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base, declared_attr

Base = declarative_base()

class Mixin(object):
    a = Column(Integer)

    @declared_attr
    def b(cls):
        return Column(Integer)

class A(Mixin, Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)

class B(A):
    __tablename__ = 'b'
    id = Column(Integer, ForeignKey('a.id'), primary_key=True)

assert 'a' in A.__table__.c
assert 'b' in A.__table__.c
assert 'a' not in B.__table__.c
assert 'b' not in B.__table__.c
1
zzzeek 15 sept. 2012 à 02:03

Je viens de rencontrer le même problème. Il s'avère que si vous définissez des colonnes dans votre classe mixin à l'aide de @declared_attr, SQLAlchemy se comporte correctement. Les colonnes déclarées directement dans la fuite de mixage dans les sous-classes lors de l'utilisation de l'héritage de table jointe.

0
Kiran Jonnalagadda 14 sept. 2012 à 16:27
7670460