【问题标题】:Many to Many Cardinal Direction Database Scheme Design多对多基本方向数据库模式设计
【发布时间】:2018-08-19 09:51:26
【问题描述】:

我对数据库设计相当陌生,可以就如何为学习项目设置架构提出一些建议。这个想法就像 Zork 这样的基于文本的冒险游戏。

获取 Room 数据库表:

class Room(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(64), index=True)
    description = db.Column(db.String(512))

    north = db.Column(db.Integer, db.ForeignKey('room.id'))
    east = db.Column(db.Integer, db.ForeignKey('room.id'))
    west = db.Column(db.Integer, db.ForeignKey('room.id'))
    south = db.Column(db.Integer, db.ForeignKey('room.id'))

当用户在一个房间里时,他们可以向南、向北等方向移动。这些房间是链接在一起的。我觉得让外键成为表的一部分是错误的方法。我正在使用 postgres 和 sqlalchemy。我觉得有一种方法可以设计这些链接,而无需手动管理房间是否从数据库中删除等。

links_table = db.Table('directions',
    db.Column('north_id', db.Integer, db.ForeignKey('room.id')),
    db.Column('west_id', db.Integer, db.ForeignKey('room.id')),
    db.Column('east_id', db.Integer, db.ForeignKey('room.id')),
    db.Column('south_id', db.Integer, db.ForeignKey('room.id')))

这样的事情会是朝着正确方向迈出的一步吗?还是我需要一张north_to_south、south_to_north 的表格?

 north_to_south = db.Table('north_to_south',
    db.Column('north_id', db.Integer, db.ForeignKey('room.id')),
    db.Column('south_id', db.Integer, db.ForeignKey('room.id')))

【问题讨论】:

    标签: python database sqlalchemy schema


    【解决方案1】:

    不完全确定 SQL DB 是否是存储此类地图的正确工具,但您走在正确的轨道上,因为方向可以存储在 association table 或 SQLAlchemy 术语中,使用association object 模式。您可以通过制作关联表(例如(src_id, dst_id, dir))来使您的模型更加灵活:

    class Direction(db.Model):
        # Let the DB cascades remove directions, if a room is deleted.
        src_id = db.Column(db.ForeignKey('room.id', ondelete='CASCADE'),
                           primary_key=True)
        dst_id = db.Column(db.ForeignKey('room.id', ondelete='CASCADE'),
                           primary_key=True)
        # A point for further normalization, create a table for enumerating
        # direction labels.
        dir = db.Column(db.String(16), primary_key=True)
    
        # Since this model has multiple foreign keys referencing the same
        # target model, the relationships must be told which one to use.
        src = db.relationship('Room', foreign_keys=[src_id],
                              back_populates='directions')
        dst = db.relationship('Room', foreign_keys=[dst_id])
    

    这还允许您使用另一个不错的 SQLAlchemy 功能:mapping a collection of related objects as a dictionary:

    from sqlalchemy.orm.collections import attribute_mapped_collection
    
    class Room(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(64), index=True)
        description = db.Column(db.String(512))
    
        directions = db.relationship(
            'Direction', collection_class=attribute_mapped_collection('dir'),
            foreign_keys='[Direction.src_id]', passive_deletes=True,
            back_populates='src')
    

    填写路线有点麻烦:

    In [33]: r1 = Room(title='r1')
    
    In [34]: r2 = Room(title='r2')
    
    In [35]: r3 = Room(title='r3')
    
    In [36]: r4 = Room(title='r4')
    
    In [37]: r5 = Room(title='r5')
    
    In [39]: for dir_, dst in zip(['north', 'east', 'south', 'west'],
        ...:                      [r2, r3, r4, r5]):
        ...:     r1.directions[dir_] = Direction(dir=dir_, dst=dst)
        ...:     
    
    In [40]: db.session.add(r1)
    
    In [41]: db.session.commit()
    

    请注意,您必须同时使用方向作为键并将其传递给Direction 构造函数。理想情况下,您根本不必处理Direction。这可以使用association proxy 来实现:

    from sqlalchemy.ext.associationproxy import association_proxy
    
    class Room(db.Model):
        ...
        dirs = association_proxy(
            'directions', 'dst',
            creator=lambda dir_, dst: Direction(dir=dir_, dst=dst))
    

    之后更容易添加路线:

    In [87]: r6 = Room(title='r6')
    
    In [88]: r2.dirs['up'] = r6
    

    这使得访问给定变量的方向变得容易:

    In [79]: where_to = input()
    west
    
    In [80]: r1.dirs[where_to]
    Out[80]: <__main__.Room at 0x7fa652e4a320>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 2012-09-30
      • 1970-01-01
      • 1970-01-01
      • 2019-06-12
      相关资源
      最近更新 更多