Skip to content

Flatting nested field to array in Flask API #786

Open
@datawookie

Description

@datawookie

I asked this question on StackOverflow (here) but didn't get any help there. I'm sure that there is a simple answer to this.

I'm using flask_restplus to build an API.

I have two models:

model_barcode = api.model('Barcode', {
        'code': fields.String,
    })

and

model_product = api.model('Product', {
        'id': fields.Integer,
        'name': fields.String,
        'barcodes': fields.Nested(model_barcode, as_list=True),
    })

The relationship between Product and Barcode is many-to-many.

The API response looks like this:

[
    {
        "id": 15707,
        "name": "Jojo Leaf Eater - White",
        "barcodes": [
            {
                "code": "6009702666853"
            },
            {
                "code": "9317118010229"
            },
            {
                "code": "6009194082315"
            },
            {
                "code": "6009149569649"
            }
        ]
    }
]

However, since the contents of the barcode model are just a single field I want it to marshal like this instead:

[
    {
        "id": 15707,
        "name": "Jojo Leaf Eater - White",
        "barcodes": ["6009702666853", "9317118010229",
                     "6009194082315", "6009149569649"]
    }
]

How would I do this?

I've tried wrapping the call to fields.Nested() in fields.List() but that did not help.

If anybody has an idea of how to make this work, I'd really appreciate the help!

Thanks.

Background Information

Here are the relevant package versions:

Flask==1.1.1
flask-restplus==0.13.0
marshmallow==3.3.0
SQLAlchemy==1.3.11
simplejson==3.17.0

Database Classes

Here are the definitions of the SQLAlchemy classes:

class Product(Base):
    __tablename__ = 'product'

    id                  = Column(Integer, primary_key=True)
    name                = Column(String(256))
    barcodes            = relationship('Barcode',
                                       secondary='product_barcode',
                                       back_populates='products')

class Barcode(Base):
    __tablename__ = 'barcode'

    id                  = Column(Integer, primary_key=True)
    code                = Column(String(15))
    products            = relationship('Product',
                                       secondary='product_barcode',
                                       back_populates='barcodes')

Alternative Implementation

I have a working implementation using Marshmallow.

from marshmallow import Schema, fields

class BarcodeSchema(Schema):
    class Meta:
        fields = ('id', 'code',)

class ProductDetailSchema(Schema):
    barcodes = fields.Pluck(BarcodeSchema, "code", many=True)
    class Meta:
        fields = ('id', 'name', 'barcodes')
        ordered = False

This does precisely what I want. However I'd really prefer to use flask_restplus models because they make the code for the actual API a lot neater.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions