Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flatting nested field to array in Flask API #786

Open
datawookie opened this issue Mar 13, 2020 · 1 comment
Open

Flatting nested field to array in Flask API #786

datawookie opened this issue Mar 13, 2020 · 1 comment

Comments

@datawookie
Copy link

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.

@aqibgatoo
Copy link

Though late to the party but you could have done it easliy like this
'barcodes': fields.List(fields.String, attribute=lambda p: [product.code for product in p.barcodes])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants