Modeling relationships in SQLAlchemy to show nested “sets” with Marshmallow

依然范特西╮ 提交于 2020-02-07 05:30:27

问题


I'm trying to figure out how to model (flask-)SQLAlchemy and (flask-)Marshamallow to provide the following JSON output.

The parent is a product and the children are "variant sets"... which are types of options, like "color" or "size". Nested within those sets I want the options themselves (S, M, L, etc.)

Seems like I'm missing something obvious.

Desired output:

{
  "skuid": "B1234",
  "name": "Test Product 1",
  "variant_sets": [
    {
        "variant_set": "B1234_1",
        "variants": [
            {
                "code": "S",
                "variant_type": "size",
                "description": "Small
            }, 
            {
                "code": "M",
                "variant_type": "size",
                "description": "Medium
            },
            {
                "code": "L",
                "variant_type": "size",
                "description": "Large
            }
        ]
    },
    {
        "variant_set": "B1234_2",
        "variants": [
            {
                "code": "RD",
                "variant_type": "color",
                "description": "Small
            }, 
            {
                "code": "GR",
                "variant_type": "color",
                "description": "Green
            },
            {
                "code": "YL",
                "variant_type": "color",
                "description": "Yellow
            }
        ]
    }
  ]
}

The marshmallow schemas I have thus far:

class ProductToOptionSchema(ma.ModelSchema):
    variants = ma.Nested(OptionSchema, many=True)

    class Meta:
        model = ProductToOption


class ProductSchema(ma.ModelSchema):
    variant_sets = ma.Nested(ProductToOptionSchema, many=True)

    class Meta:
        model = Product

When I try this code:

product = Product.query.filter_by(skuid="B1234").first()
product_schema = ProductSchema()
result = product_schema.jsonify(product)

The error I get is:

TypeError: 'Option' object is not iterable

The products are related to variants (options) through a secondary table. The models I have so far are:

products

-----------------------------
| skuid | name              |
-----------------------------
| B1234 | Test Product 1    |
-----------------------------
| B1235 | Test Product 2    |
-----------------------------

class Product(db.Model):
    __tablename__ = 'products'

    skuid = db.Column(db.String(16), primary_key=True)
    name = db.Column(db.String(128))
    variants = db.relationship("Option", secondary="products_to_options")

products_to_options

------------------------
| skuid | variant_set  |
------------------------
| B1234 | B1234_1      |
------------------------
| B1234 | B1234_2      |
------------------------
| B1235 | B1235_1      |
------------------------

class ProductToOption(db.Model):
    __tablename__ = 'products_to_options'

    skuid = db.Column(db.String(16), db.ForeignKey('products.skuid'), nullable=False)
    variant_set = db.Column(db.String(16), db.ForeignKey('options.variant_set'), nullable=False)

    products = db.relationship('Product', foreign_keys="ProductToOption.skuid")
    variants = db.relationship('Option', foreign_keys="ProductToOption.variant_set")

options

-----------------------------------------------------
| variant_set | code | variant_type | description   |
-----------------------------------------------------
| B1234_1     | S    | size         | Small         |
-----------------------------------------------------
| B1234_1     | M    | size         | Medium        |
-----------------------------------------------------
| B1234_1     | L    | size         | Large         |
-----------------------------------------------------
| B1234_2     | RD   | color        | Red           |
-----------------------------------------------------
| B1234_2     | GR   | color        | Green         |
-----------------------------------------------------
| B1234_2     | YL   | color        | Yellow        |
-----------------------------------------------------
| B1235_1     | OK   | wood         | Oak           |
-----------------------------------------------------
| B1235_1     | CH   | wood         | Cherry        |
-----------------------------------------------------

class Option(db.Model):
    __tablename__ = 'options'

    variant_set = db.Column(db.String(16), nullable=False)
    code = db.Column(db.String(8), nullable=False)
    variant_type = db.Column(db.String(16), nullable=False)
    description = db.Column(db.String(16), nullable=False)

    product = db.relationship("Product", secondary="products_to_options")

回答1:


Think I figured this out. I modified the SQLAlchemy relationships between the tables and removed the "secondary" attribute. The relationship is now:

skuid -> variant_set -> variants

And that seems to work. Or at least, I'm getting my desired output.

class Product(db.Model):
    __tablename__ = 'products'

    skuid = db.Column(db.String(16), primary_key=True)
    name = db.Column(db.String(128))
    variant_sets = db.relationship("ProductToOption")

class ProductToOption(db.Model):
    __tablename__ = 'products_to_options'

    id = db.Column(db.INTEGER, primary_key=True)
    skuid = db.Column(db.String(36), db.ForeignKey('products.skuid'), nullable=False)
    options_code = db.Column(db.String(36), nullable=False)

    variants = db.relationship('Option')

class Option(db.Model):
    __tablename__ = 'options'

    variant_set = db.Column(db.String(16), db.ForeignKey('products_to_options.options_code'), nullable=False)
    code = db.Column(db.String(8), nullable=False)
    variant_type = db.Column(db.String(16), nullable=False)
    description = db.Column(db.String(16), nullable=False)


来源:https://stackoverflow.com/questions/58806675/modeling-relationships-in-sqlalchemy-to-show-nested-sets-with-marshmallow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!