Aterus
Aterus

Reputation: 564

Flask-RESTPlus: How to get result of query sqlite database in nested API model?

I'm writing an api with Flask-RESTPlus and want to use a sqlite database First my current code:

API Models

lightstate = api.model('LightState', {
    'red': fields.Integer(description='red part of the rgb light'),
    'green': fields.Integer(description='green part of the rgb light'),
    'blue': fields.Integer(description='blue part of the rgb light'),
    'bri': fields.Integer(description='brightness of the light')    
})
lights = api.model('Lights', {
    'id': fields.Integer(readOnly=True, description='The database id of the light'),
    'name': fields.String(required=True, description='light name'),
    'state': fields.Nested(lightstate)
})

Database Model

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Lights(db.Model):
    __bind_key__ = 'lights'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    red = db.Column(db.Integer)
    green = db.Column(db.Integer)
    blue = db.Column(db.Integer)
    bri = db.Column(db.Integer)

    def __init__(self, name, red, green, blue, bri):
        self.name = name
        self.red = red
        self.green = green
        self.blue = blue
        self.bri = bri

Create Database Entry

def create_light(data):
    name = data.get('name')
    state = data.get('state')
    red = state['red']
    green = state['green']
    blue = state['blue']
    bri = state['bri']
    entry = Lights(name, red, green, blue, bri)
    db.add(entry)

Request Handler

@namespace.route('/')
class Light(Resource):
    @api.marshal_with(lights)
    def get(self):
        lights_data = Lights.query.all()
        return lights_data

    @api.expect(lights)
    def post(self):
        create_light(request.json)
        return None, 200

As you can see, I want to store the name, rbg values and the brightness of lights in a database. Writing the datebase by using the post request works fine. But the result of the get request looks like this:

[
  {
    "id": 1,
    "name": "garden",
    "state": {
      "red": null,
      "green": null,
      "blue": null,
      "bri": null
    }
  },
  {
    "id": 2,
    "name": "pool",
    "state": {
      "red": null,
      "green": null,
      "blue": null,
      "bri": null
    }
  }
]

As you can see, the light values are null. I know, that my problem has something to with the nested fields in my API Models definition, because when I put all parts in one model, it works.

Changed API Model

lights = api.model('Lights', {
    'id': fields.Integer(readOnly=True, description='The database id of the light'),
    'name': fields.String(required=True, description='light name'),
    'red': fields.Integer(description='red part of the rgb light'),
    'green': fields.Integer(description='green part of the rgb light'),
    'blue': fields.Integer(description='blue part of the rgb light'),
    'bri': fields.Integer(description='brightness of the light')
})

Output get request

[
  {
    "id": 1,
    "name": "garden",
    "red": 50,
    "green": 205,
    "blue": 50,
    "bri": 84
  },
  {
    "id": 2,
    "name": "pool",
    "red": 255,
    "green": 0,
    "blue": 255,
    "bri": 96
  }
]

How can I get the values from my database in the "state" key?

Upvotes: 1

Views: 257

Answers (1)

Aterus
Aterus

Reputation: 564

I have found an answer to this question, I want to share.

You just need to add attribute=lambda x: x as an argument for the nested field of the api model.

Full example:

lights = api.model('Lights', {
    'id': fields.Integer(readOnly=True, description='The database id of the light'),
    'name': fields.String(required=True, description='light name'),
    'state': fields.Nested(lightstate, attribute=lambda x: x)
})

Upvotes: 1

Related Questions