2012-01-07 1 views
6

Son zamanlarda tırmanma alanları ve yolları içeren bir proje için SQL Alchemy ile çalışmaya başladı. Alanlar hiyerarşiktir, çünkü tek bir alan birden fazla alan içerebilir ve bu da diğer alanları içerebilir. Bir yol doğrudan tek bir alanla ilişkilendirilir, ancak aynı zamanda o alanın ebeveyni vb. Ile de ilişkilidir.SQL Alchemy Closure Tablo İlişki Tanımı

Bunu uygulamak için bir closure table ala Bill Karwin kullanmayı seçtim. Kapatma tablosu uygulamasında, atası/iniş bilgisini saklamak için ikinci bir tablo oluşturulur. Bir düğüm eklendiğinde, bir öz referanslama satırı ve ayrıca ağaçtaki her ata için bir satır oluşturulur. aşağıdaki gibi

tablo yapısı (basitleştirilmiş) olduğu:

-- area -- 
area_id 
name 

-- area_relationship -- 
ancestor 
descendent 

-- route -- 
route_id 
area_id 
name 

Örnek veri:

-- area -- 
1, New River Gorge 
2, Kaymoor 
3, South Nuttall 
4, Meadow River Gorge 

-- area_relationship (ancestor, descendent) -- 
1, 1 (self-referencing) 
2, 2 (self-referencing) 
1, 2 (Kaymoor is w/i New River Gorge) 
3, 3 (self-referencing) 
1, 3 (South Nutall is w/i New River Gorge) 
4, 4 (self-referencing) 

-- route (route_id, area_id, name) 
1, 2, Leave it to Jesus 
2, 2, Green Piece 
3, 4, Fancy Pants 

(ağacın kadar) belirli bir rota için tüm alanlar için sorgulamak için, ben yürütebilirsiniz:

SELECT area.area_id, area.name 
FROM route 
    INNER JOIN area_relationship ON route.area_id = area_relationship.descendent 
    INNER JOIN area ON area.area_id = area_relationship.ancestor 
WHERE route.route_id = 1 

Benzer şekilde, belirli bir alandaki (alçalma alanları dahil) tüm rotaları şu şekilde sorgulayabilirim: -

class DbArea(Base): 

    __tablename__ = 'area' 

    area_id = Column(Integer, primary_key = True) 
    name = Column(VARCHAR(50)) 
    created = Column(DATETIME) 

    area_relationship_table.c.ancestor]) 

    descendents = relationship('DbArea', backref = 'ancestors', 
     secondary = area_relationship_table, 
     primaryjoin = area_id == area_relationship_table.c.ancestor, 
     secondaryjoin = area_id == area_relationship_table.c.descendent) 

DbRoute sınıfı -

class DbRoute(Base): 

     __tablename__ = 'route' 

     route_id = Column(Integer, primary_key = True) 
     area_id = Column(Integer, ForeignKey('area.area_id')) 
     name = Column(VARCHAR(50)) 
     created = Column(DATETIME) 

     area = relationship("DbArea") 

     areas = relationship('DbArea', backref = 'routes', 
      secondary = area_relationship_table, 
      primaryjoin = area_id == area_relationship_table.c.ancestor, 
      secondaryjoin = area_id == area_relationship_table.c.descendent, 
      foreign_keys=[area_relationship_table.c.ancestor, 
      area_relationship_table.c.descendent]) 

area_relationship_table = Table('area_relationship', Base.metadata, 
    Column('ancestor', Integer, ForeignKey('area.area_id')), 
    Column('descendent', Integer, ForeignKey('area.area_id')) 
) 

DbArea sınıfı: Ben bu ilişkileri işlemek için bir ilişki ve iki tablo oluşturduk SQL Simyada

SELECT route.route_id, route.name 
FROM area 
    INNER JOIN area_relationship ON area.area_id = area_relationship.ancestor 
    INNER JOIN route ON route.area_id = area_relationship.descendent 
WHERE area.area_id = 1 

Şu anda, ben DbRoute'daki bölgeler ilişkisini kullanarak, tekil güzergahtaki alanları belirleyebilme. Ancak, ben DbArea içinde backref 'yolları' kullanmayı deneyin, aşağıdaki hatayı alıyorum:

sqlalchemy.exc.StatementError: Hayır sütun route.area_id mapper Mapper yapılandırılır | DbArea | alan ... (orijinal Nedeni: UnmappedColumnError: Eşleştirilmemiş Mapper | DbArea | alanı üzerinde route.area_id sütun yok ...) 'route.route_id AS route_route_id, route.area_id AS route_area_id, route.name, route_name, route.created AS route_created \ nFROM route , area_relationship \ nWHERE% s = alan_relationship.descendent VE route.area_id = alan_relationship.ancestor '[immutabledict ({})]

Sanırım ilişkiyi kurmak için DbArea'ya bir şey eklemem gerekiyor sanırım, ama sonra bazı farklı seçeneklerle deneme yapmak, çözümü belirleyemedi.

cevap

6

SQL Alchemy Google Grubu'na gönderme ve bazı awesome help from Michael Bayer aldıktan sonra, düzgün birleştirmeler anahtar tanımlanmasında gerçekten DbRoute sınıfının

areas = relationship('DbArea', 
    backref = backref('routes', order_by = 'DbRoute.name'), 
    secondary = area_relationship_table, 
    primaryjoin = area_id == area_relationship_table.c.descendent, 
    secondaryjoin = DbArea.area_id == area_relationship_table.c.ancestor, 
    innerjoin = True, order_by = DbArea.name, 
    foreign_keys = 
     [area_relationship_table.c.ancestor, 
      area_relationship_table.c.descendent]) 

alanlar ilişkinin aşağıdaki tanım geldi. Artık bir rota örneğinden kolayca geçebilir ve ata ağaçtaki veya bir bölgedeki alanları bulabilir ve alt ağaçtaki tüm rotaları bulabilirim.