Flask-RESTPlus: как получить результат запроса базы данных sqlite во вложенной модели API?

#python #sql #flask #sqlalchemy #flask-restplus

#python #sql #flask #sqlalchemy #flask-restplus

Вопрос:

Я пишу api с помощью Flask-RESTPlus и хочу сначала использовать базу данных sqlite в своем текущем коде:

Модели API

 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)
})

 

Модель базы данных

 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
 

Создать запись базы данных

 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)
 

Обработчик запроса

 @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
 

Как вы можете видеть, я хочу сохранить имя, значения rbg и яркость источников света в базе данных. Запись базы данных с помощью post-запроса работает нормально.
Но результат запроса get выглядит следующим образом:

 [
  {
    "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
    }
  }
]
 

Как вы можете видеть, значения light равны нулю. Я знаю, что моя проблема связана с вложенными полями в определении моих моделей API, потому что, когда я помещаю все части в одну модель, это работает.

Измененная модель API

 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')
})
 

Вывод запроса get

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

Как я могу получить значения из моей базы данных в ключе «состояние»?

Комментарии:

1. Вы проверяли, установлены ли значения вообще в БД? Другими словами, что возвращает ваша БД при запуске SELECT * FROM Lights после отправки запроса post?

2. Все значения заданы в БД. Смотрите мой последний пост «code». Это не проблема.

Ответ №1:

Я нашел ответ на этот вопрос, которым хочу поделиться.

Вам просто нужно добавить attribute=lambda x: x в качестве аргумента вложенное поле модели api.

Полный пример:

 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)
})