我对数据库设计还不熟悉,可以就如何为学习项目设置模式提供一些建议。这个想法就像Zork这样的基于文本的冒险游戏。
拿一个房间数据库表:
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')))
答案 0 :(得分:0)
不完全确定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
构造函数。理想情况下,您根本不需要处理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>