0

我有一个现有的数据库架构,它使用整数作为主键,并且需要向每个表添加第二个 UUID 列。这个 UUID 是服务的消费者在引用记录时将使用的,现有的整数 ID 将保持私有并且仅在内部使用。下面是一个简化的例子。事务表具有 TransactionID 和 TransactionUUID 列,并且还具有指向 Category 表的外键 CategoryID。同样,Category 表具有 CategoryID 和 CategoryUUID 列。

+------------+--------------------------------------+------+
| CategoryID | CategoryUUID                         | Name |
+------------+--------------------------------------+------+
|          1 | f9aafcf6-8cc7-4f1e-a847-bfbb0297bc5f | Foo  |
|          2 | 1cf892e3-c100-4542-bfd1-131ba8a18c17 | Bar  |
+------------+--------------------------------------+------+

+---------------+--------------------------------------+---------+---------------------+------------+
| TransactionID | TransactionUUID                      | Amount  | Time                | CategoryID |
+---------------+--------------------------------------+---------+---------------------+------------+
|             1 | 48182040-beb5-4df8-98fe-c3f6f5557cc0 | 55.0000 | 2021-07-15 09:56:11 |          2 |
+---------------+--------------------------------------+---------+---------------------+------------+
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from marshmallow import fields, post_load


db = SQLAlchemy()
ma = Marshmallow()


class Category(db.Model):
    __tablename__ = 'Category'
    id = db.Column('CategoryID', db.Integer, primary_key=True)
    uuid = db.Column('CategoryUUID', db.CHAR(36), unique=True, nullable=False)
    name = db.Column('Name', db.String(64), nullable=False)
    transactions = db.relationship('Transaction', back_populates='category')


class CategorySchema(ma.Schema):
    uuid = fields.UUID()
    name = fields.Str()

    @post_load
    def make_category(self, data, **kwargs):
        return Category(**data)


class Transaction(db.Model):
    __tablename__ = 'Transaction'
    id = db.Column('TransactionID', db.Integer, primary_key=True)
    uuid = db.Column('TransactionUUID', db.CHAR(36), unique=True, nullable=False)
    amount = db.Column('Amount', db.DECIMAL, nullable=False)
    time = db.Column('Time', db.DateTime, nullable=False)
    category_id = db.Column('CategoryID', db.Integer, db.ForeignKey('Category.CategoryID'), nullable=False)
    category = db.relationship('Category', back_populates='transactions')


class TransactionSchema(ma.Schema):
    uuid = fields.UUID()
    amount = fields.Decimal()
    time = fields.DateTime()
    category_uuid = fields.UUID()

    @post_load
    def make_transaction(self, data, **kwargs):
        return Transaction(**data)

我想要实现的是允许对事务资源的发布请求以允许创建新事务,并以某种方式将 TransactionSchema 类中的 category_uuid 字段链接到相应的 category_id。我面临的挑战是在序列化和反序列化对象时如何将 UUID 与其对应的整数 ID 相关联。例如,当一个新事务被创建并且消费者通过这样的有效负载发布时:

{
    "uuid": "7f68e33f-c5d2-41c8-9826-5df904722a1a",
    "amount": 10.00,
    "time": "2021-07-17T04:50:25+00:00",
    "category_uuid": "f9aafcf6-8cc7-4f1e-a847-bfbb0297bc5f"
}

JSON 对象反序列化如下:

transaction = TransactionSchema().load({...})

Transaction 类没有 category_uuid 属性,需要以某种方式将此值转换为相应的整数 ID。同样,当像这样序列化事务时:

json = TransactionSchema().dump(transaction)

category_id 属性需要翻译成对应的 category_uuid 值。

sqlalchemy 中是否有一种优雅的方式来实现这种 ID 映射?

4

1 回答 1

0

post_load一种方法是pre_dump使用marshmallow. 这是代码:

from marshmallow import fields, post_load, pre_dump

class TransactionSchema(ma.Schema):
    uuid = fields.UUID()
    amount = fields.Decimal()
    time = fields.DateTime()
    category_uuid = fields.UUID()

    @post_load
    def make_transaction(self, data, **kwargs):
        data["category_id"] = Category.query.filter_by(
            uuid=str(data["category_uuid"])
        ).all()[0].id
        del data["category_uuid"]
        return Transaction(**data)
    
    @pre_dump
    def serialize_transaction(self, obj, **kwargs):
        obj.category_uuid = obj.category.uuid
        return obj

通过这种方式,您可以在(反)序列化事务时获得自动转换。

于 2021-07-22T06:59:29.190 回答