简短的回答是视情况而定。
答案很长,这取决于您存储的内容以及所述车辆的品牌以及您希望添加新类型的频率。
如果您需要存储的不仅仅是每个品牌的名称,还需要一些额外的元数据,例如油箱的大小、货物空间,甚至是排序键,请使用附加表。这样一个小表的开销是最小的,如果你使用 make ids 而不是 make names 与前端通信,这完全没有问题。只需记住将索引添加到 vehicle.make_id 以提高查找效率。
class VehicleMake(Model):
id = Column(Integer, primary_key=True)
name = Column(String(16))
cars = relationship('Vehicle', back_populates="make", lazy='dynamic')
class Vehicle(Model):
id = Column(Integer, primary_key=True)
name = Column(String(32))
make_id = Column(Integer, ForeignKey('vehicle_make.id'), nullable=False)
make = relationship("VehicleType", innerjoin=True)
Vehicle.query.get(1).make.name # == 'Ford', the make for vehicle 1
Vehicle.query.filter(Vehicle.make_id == 2).all() # all Vehicles with make id 2
Vehicle.query.join(VehicleMake)\
.filter(VehicleMake.name == 'Ford').all() # all Vehicles with make name 'Ford'
如果您不需要存储任何元数据,则不再需要单独的表。但是,字符串的一般问题是拼写错误和大写/小写字母会破坏数据一致性的风险很高。如果您不需要添加太多新产品,最好使用Enums,SQLAlchemy 中甚至还有 MySQL 特定的。
import enum
class VehicleMake(enum.Enum):
FORD = 1
DODGE = 2
CHEVROLET = 3
class Vehicle(Model):
id = Column(Integer, primary_key=True)
name = Column(String(32))
make = Column(Enum(VehicleMake), nullable=False)
Vehicle.query.get(1).make.name # == 'FORD', the make for vehicle 1
Vehicle.query.filter(Vehicle.make == VehicleMake(2)).all() # all Vehicles with make id 2
Vehicle.query.filter(Vehicle.make == VehicleMake.FORD).all() # all Vehicles with make name 'Ford'
枚举的主要缺点是它们可能难以使用新值进行扩展,尽管至少对于 Postgres 方言特定版本比一般的 SQLAlchemy 版本要好得多,请查看sqlalchemy.dialects.mysql.ENUM。虽然如果你想扩展你现有的枚举,你总是可以在你的 Flask-Migrate/Alembic 迁移中执行raw SQL。
最后,使用字符串的好处。主要是,您可以始终以编程方式强制执行数据一致性。但是,这是以您必须以编程方式强制执行数据一致性为代价的。如果外部用户甚至同事可以更改或插入车辆制造商,除非您对进入数据库的内容非常严格,否则这会给您带来麻烦。例如,将所有值大写以方便分组可能会很好,因为它有效地减少了可能出错的程度。您可以在编写过程中这样做,也可以在sqlalchemy.func.upper(Vehicle.make) 上添加索引并使用hybrid properties 始终查询大写值。
class Vehicle(Model):
id = Column(Integer, primary_key=True)
name = Column(String(32))
_make = Column('make', String(16))
@hybrid_property
def make(self):
return self._make.upper()
@make.expression
def make(cls):
return func.upper(cls._make)
Vehicle.query.get(1).make.upper() # == 'FORD', the make for vehicle 1
Vehicle.query.filter(Vehicle.make == 'FORD').all() # all Vehicles with make name 'FORD'
在做出选择之前,还要考虑一下您希望如何向用户展示它。如果他们应该能够自己添加新选项,请使用字符串或单独的表格。如果要显示可能性的下拉列表,请使用枚举或表格。如果您有一个空数据库,那么很难收集所有字符串值以显示在前端,而无需将其作为列表存储在 Flask 环境中的某个位置。