Как прочитать параметр запроса GET в среде RESTful Flask/SQLAlchemy/Marshmallow

Я работал над парой руководств перед Рождеством, и теперь я пытаюсь вернуться к тому, с чего я ушел. Пытаюсь научить себя REST, создав несколько простых конечных точек API. Мое замешательство связано с тем, что я не могу найти учебники, которые использовал, и, похоже, есть несколько разных способов решить проблему. Так что теперь я не уверен, как правильно это сделать. Код работает для возврата всех клиентов в БД, теперь я хочу вернуть конкретного клиента на основе его идентификатора

Хорошо, это то, что у меня есть...

У меня есть app.py, который определяет ресурс следующим образом:

api.add_resource(CustomerResource, '/Customer')

У меня есть models.py, который определяет класс клиента следующим образом:

ma = Marshmallow()
db = SQLAlchemy()

class Customer(db.Model):
    __tablename__ = 'customers'
    __table_args__ = {"schema":"business"}
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text, nullable=False)
    status = db.Column(db.Integer, nullable=False)

class CustomerSchema(ma.Schema):
    id = fields.Integer()
    name = fields.String(required=True)
    status = fields.Integer(required=True)

У меня есть customer.py, который определяет класс клиента следующим образом:

customers_schema = CustomerSchema(many=True)
customer_schema = CustomerSchema()

class CustomerResource(Resource):
    def get(self):
        customers = Customer.query.all()
        customers = customers_schema.dump(customers)
        return {'status': 'success', 'data': customers}, 200

Я пытался использовать request.args, но я не верю, что это правильный путь, потому что он станет неподдерживаемым.

Таким образом, все вышеперечисленное работает с GET, успешно возвращающим всех клиентов. Но теперь я хочу иметь возможность использовать GET http://127.0.0.1:5000/api/Customer/10 и просто вернуть детали для идентификатора клиента = 10

Я не уверен, нужно ли мне определять новый ресурс или можно изменить существующий CustomerResource, чтобы проверить наличие параметра.

Любое руководство приветствуется...


person The Welsh Dragon    schedule 29.01.2019    source источник


Ответы (1)


Да, вы правы, не используйте метод request.args, вместо этого создайте другой ресурс. Помните, что api.add_resource по существу просто сопоставляет обработчик с конечной точкой RESTFUL. Если у вас есть много дублированного кода бизнес-логики, совместно используемого между конечными точками, я бы посоветовал вам вынести эту бизнес-логику во вспомогательную функцию и использовать эту вспомогательную функцию внутри ваши определения ресурсов, но в данном конкретном случае это не обязательно. Я бы подумал о следующем:

app.py:

api.add_resource(CustomerList, '/Customer')
api.add_resource(Customer, '/Customer/<int:id>')

Я бы переименовал файл customer.py во что-то вроде route.py, и он содержал бы следующее:

class CustomerList(Resource):
    def get(self):
        customers = Customer.query.all()
        customers = customers_schema.dump(customers)
        return {'status': 'success', 'data': customers}, 200

class Customer(Resource):
    def get(self, id):
        customer = Customer.query.filter_by(id=id).first()
        customer, errors = customers_schema.dump(customer)
        if errors:
           return jsonify(errors), 422
        return customer, 200

Сохраните файл models.py как есть, и я бы рассмотрел возможность использования метода jsonify, который flask предоставляет для возврата ваших данных в ваши конечные точки RESTFUL. Я показал пример этого в конечной точке конкретного клиента.

Надеюсь, это поможет!

person Nathan    schedule 29.01.2019
comment
Спасибо, Натан. Я внес те изменения, которые вы предложили. Запрос для всех клиентов все еще работает. Запрос для конкретного клиента приводит к ошибке TypeError: 'Customer' object is not iterable error для строки customer = Customer.query.filter_by(id=id).first(). Есть идеи, почему? - person The Welsh Dragon; 29.01.2019
comment
Привет, это может быть ошибка приведения, так как первичный ключ вашей таблицы Customer является целым числом, попробуйте изменить ресурс, специфичный для вашего клиента, на следующее: api.add_resource(Customer, '/Customer/‹int:id›' и дайте мне знать, если это разрешится проблема Если нет, я могу взглянуть на ваш код, если вы дадите мне ссылку на него :) - person Nathan; 29.01.2019
comment
Спасибо, Натан. Неитерируемая ошибка была моей ошибкой, и я ее исправил. У меня есть другая проблема, хотя в предложенной вами строке customer, errors = customers_schema.dump(customer) возникает следующая ошибка ValueError: слишком много значений для распаковки (ожидается 2) Я отредактировал исходный пост, чтобы показать, где объявлена ​​схема. Но, боюсь, я совсем не понимаю эту часть - она ​​взята из туториала. - person The Welsh Dragon; 29.01.2019
comment
Хорошо, не беспокойтесь, я посмотрю немного - person Nathan; 29.01.2019
comment
ОК, отвечая на мой предыдущий комментарий. Проблема в том, что версия Marshmallow, которую я использую, больше не возвращает данные, ошибки — она просто возвращает десериализованные данные. Согласно этому ответу link - person The Welsh Dragon; 29.01.2019
comment
Последний вопрос. Что мне нужно изменить, чтобы поддерживать URL-адреса в форме /api/Customer/?id=1 - person The Welsh Dragon; 29.01.2019
comment
Я рад, что у вас все получилось! Flask-Restful имеет модуль разбора запросов, называемый reqparse: flask-restful.readthedocs.io/en/0.3.6/reqparse.html но он устаревает, поэтому я бы проверил WebArgs для этой функциональности если это необходимо: github.com/marshmallow-code/webargs/ blob/dev/examples/ Я связал пример flask-restful с их документации. Надеюсь, это поможет! - person Nathan; 29.01.2019
comment
Еще раз спасибо, это было именно то, что я искал! - person The Welsh Dragon; 29.01.2019