I have an existing database schema that uses integers for primary keys and need to add a second UUID column to each table. This UUID is what consumers of the service will use when referring to records and the existing integer IDs will remain private and only be used internally. Below is a simplified example of what this looks like. The transaction table has the columns TransactionID and TransactionUUID and it also has a foreign key CategoryID that points to the Category table. Similarly, the Category table has columns CategoryID and 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)
What I'm trying to achieve is allow post requests to the transactions resource to allow new transactions to be created and somehow link the category_uuid field from the TransactionSchema class to the corresponding category_id. The challenge I'm having is working out how to associate a UUID with its corresponding integer ID when serializing and de-serializing objects. For example, when a new transaction is created and a consumer posts through a payload like this:
{
"uuid": "7f68e33f-c5d2-41c8-9826-5df904722a1a",
"amount": 10.00,
"time": "2021-07-17T04:50:25+00:00",
"category_uuid": "f9aafcf6-8cc7-4f1e-a847-bfbb0297bc5f"
}
The JSON object is de-serialized like this:
transaction = TransactionSchema().load({...})
The Transaction class doesn't have a category_uuid attribute and needs to somehow translate this value to the corresponding integer ID. Similarly when serializing a Transaction like so:
json = TransactionSchema().dump(transaction)
The category_id attribute needs to be translated to the corresponding category_uuid value.
Is there an elegant way in sqlalchemy to achieve this mapping of IDs?