【问题标题】:Flask Class views and Blueprints test case failureFlask 类视图和蓝图测试用例失败
【发布时间】:2022-01-07 00:59:47
【问题描述】:

我正在处理一个 Flask 类视图和蓝图问题,其中需要创建路由以将学生添加到数据库和从数据库中列出。无法通过测试。失败说

TypeError: <StudentModel 1> is not JSON serializable

不确定这是否是解决问题的正确方法。请指导

StudentView.py

from flask import request, json, Response, Blueprint,jsonify
from flask import render_template
from flask_cors import CORS, cross_origin
from ..models.StudentModel import StudentModel, StudentSchema

#Add your code here
stu =Blueprint('stu', __name__,url_prefix='/api/students')
# Create routes to add a student to the database.
@stu.route('/add',methods=['POST'])
def add():

    r = request.json
    id = r['id']
    student_name=r['student_name']
    student_age=r['student_age']
    sm =StudentModel(r)
    sm.update(r)
    sm.save()
    x=sm.get_student_id(id)

    if request.method == 'POST':
        return Response(json.dumps(r),status= 201)
    
# Create routes to list all the added students

@stu.route('/')
def getstudents():
  users =StudentModel.query.all()
  return jsonify(users) 

StudentModel.py

class StudentModel(db.Model):
  
  #Table name
  __tablename__ = 'student'

  id = db.Column(db.Integer, primary_key=True)
  student_name = db.Column(db.String(128), nullable=False)
  student_age = db.Column(db.Integer, nullable=False)
  

  #class constructor
  def __init__(self, data):
    self.id = data.get('id')
    self.student_name = data.get('student_name')
    self.student_age= data.get('student_age')


  def save(self):
    db.session.add(self)
    db.session.commit()

  def update(self, data):
    for key, item in data.items():
      setattr(self, key, item)
    db.session.commit()

  def delete(self):
    db.session.delete(self)
    db.session.commit()

  @staticmethod
  def get_all_students():
    return StudentModel.query.all()

  @staticmethod
  def get_student_id(id):
    return StudentModel.query.filter_by(id=id).first()

  def __repr(self):
      return '<id {}>'.format(self.id)


class StudentSchema(Schema):
  id = fields.Int(required=True)
  student_name= fields.Str(required=True)
  student_age = fields.Int(required=True)

app.py

from src.views.StudentView import stu
app.register_blueprint(stu)

test.py

import pytest
from api import app, db
import json
import base64
from flask import Flask
import os
from src.models.StudentModel import StudentModel
from src.models.TeacherModel import TeacherModel

class Test_API:
    client  = app.test_client()
    
    @pytest.fixture(autouse=True, scope='session')
    def setUp(self):
        app.config['TESTING'] = True
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///testing.db'
        db.create_all()
        yield db
        os.remove('testing.db')

    def test_student_in_db(self):
        result  = StudentModel.query.all()
        assert len(result) == 0
        assert result == []

    def test_students_list(self):
        url = "api/students/"
        response = self.client.get(url)
        assert response.status_code == 200
        assert response.json == []

    def test_students_register_method(self):
        url = "/api/students/add"
        payload = '{"id": 1,"student_age": 16 , "student_name": "testname"}'
        headers = { 'Content-Type': "application/json",  'cache-control': "no-cache"  }
        response = self.client.post(url, data=payload, headers=headers)
        assert response.status_code == 201
        assert response.json['message'] == 'Added student to the list'
        
    
    def test_data_in_db_after_adding(self):
        result  = StudentModel.query.all()
        assert len(result) == 1
        assert result[0].student_name == 'testname'


    def test_after_adding_students(self):
        url = "api/students/"
        response = self.client.get(url)
        assert response.status_code == 200
        assert response.json == [{'id': 1, 'student_age': 16, 'student_name': 'testname'}]      

        

测试失败:

Test_API.test_after_adding_students _________________________________

self = <tests.tests_routes.Test_API object at 0x7fb88ce5df98>

    def test_after_adding_students(self):
        url = "api/students/"
>       response = self.client.get(url)

tests/tests_routes.py:49: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:1006: in get
    return self.open(*args, **kw)
/home/user/.local/lib/python3.5/site-packages/flask/testing.py:227: in open
    follow_redirects=follow_redirects,
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:970: in open
    response = self.run_wsgi_app(environ.copy(), buffered=buffered)
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:861: in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:1096: in run_wsgi_app
    app_rv = app(environ, start_response)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2463: in __call__
    return self.wsgi_app(environ, start_response)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2449: in wsgi_app
    response = self.handle_exception(e)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1866: in handle_exception
    reraise(exc_type, exc_value, tb)
/home/user/.local/lib/python3.5/site-packages/flask/_compat.py:39: in reraise
    raise value
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2446: in wsgi_app
    response = self.full_dispatch_request()
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1951: in full_dispatch_request
    rv = self.handle_user_exception(e)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1820: in handle_user_exception
    reraise(exc_type, exc_value, tb)
/home/user/.local/lib/python3.5/site-packages/flask/_compat.py:39: in reraise
    raise value
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1949: in full_dispatch_request
    rv = self.dispatch_request()
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1935: in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
src/views/StudentView.py:39: in getstudents
    return jsonify(users)
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:370: in jsonify
    dumps(data, indent=indent, separators=separators) + "\n",
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:211: in dumps
    rv = _json.dumps(obj, **kwargs)
/usr/lib/python3.5/json/__init__.py:237: in dumps
    **kw).encode(obj)
/usr/lib/python3.5/json/encoder.py:198: in encode
    chunks = self.iterencode(o, _one_shot=True)
/usr/lib/python3.5/json/encoder.py:256: in iterencode
    return _iterencode(o, 0)
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:100: in default
    return _json.JSONEncoder.default(self, o)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <flask.json.JSONEncoder object at 0x7fb88ce241d0>, o = <StudentModel 1>

    def default(self, o):
        """Implement this method in a subclass such that it returns
        a serializable object for ``o``, or calls the base implementation
        (to raise a ``TypeError``).
    
        For example, to support arbitrary iterators, you could
        implement default like this::
    
            def default(self, o):
                try:
                    iterable = iter(o)
                except TypeError:
                    pass
                else:
                    return list(iterable)
                # Let the base class default method raise the TypeError
                return JSONEncoder.default(self, o)
    
        """
>       raise TypeError(repr(o) + " is not JSON serializable")
E       TypeError: <StudentModel 1> is not JSON serializable

【问题讨论】:

    标签: python json flask sqlalchemy


    【解决方案1】:

    你可以这样做:

    from flask import request, json, Response, Blueprint
    from flask import render_template
    from flask_cors import CORS, cross_origin
    from ..models.StudentModel import StudentModel, StudentSchema
    
    #Add your code here
    stu= Blueprint('student', __name__, url_prefix="/api/students")
    
    # Create routes to add a student to the database.
    @stu.route('/add',methods=['POST'])
    def add():
        if request.method=='POST':
            r = request.get_json()
            sm =StudentModel(r)
            sm.update(r)
            sm.save()
     
            resp = json.jsonify({'message': "Added student to the list"})
            resp.status_code = 201
            return resp
    
    
    # Create routes to list all the added students
    @stu.route('/',methods=['GET'])
    def view():
        studs = StudentModel.get_all_students()
        res = [{'id':s.id, 'student_name':s.student_name, 'student_age':s.student_age} for s in studs]
        return json.jsonify(res)
    

    【讨论】:

      【解决方案2】:

      解决问题的方法是一一解决错误。

      第一个错误来自一个测试,该测试检查添加新学生的响应是否是 HTTP 代码 201(已创建),但您的代码返回 200(确定)。您的代码返回 200 的原因是因为如果您没有指定其他任何内容(并且在处理请求时没有错误),这是 Flask 的默认设置。要解决这个问题,请在网上搜索如何在 Flask 中返回自定义 http 代码。

      第二个错误来自一个测试,该测试期望在查询所有学生时出现这个先前添加的学生。从技术上讲,此测试取决于首先添加学生的第一个测试。此测试失败的原因是因为在您的 add 函数中没有与数据库的交互。检查StudentModel 上的方法并尝试使用请求数据在您的数据库中创建一个新条目。这里好的谷歌关键字是“SQLAlchemy 插入”或“SQLAlchemy 将新对象保存到数据库”。

      修复第二个错误后,第三个错误也应该消失。它还测试是否添加了用户,但更进一步使用API​​获取用户,并且它还检查是否使用了正确的用户数据。

      其余测试的工作方式非常相似,只是针对教师而不是学生。

      【讨论】:

      • 谢谢@Hubert。在您的输入的帮助下,我能够通过 2 个测试用例。但是,我坚持使用test_after_adding_students。尝试使用StudentModel.py 中定义的方法。测试用例因TypeError: &lt;StudentModel 1&gt; is not JSON serializable 错误而失败
      • 嘿@lazyEval,当你改变你的问题时,问题现在完全不同了,这有点令人困惑。我建议您尝试将问题缩小到相关的代码段并提出一个新问题。这样,编辑时不会丢失上下文。
      • 当然@Hubert 会这样做。
      猜你喜欢
      • 1970-01-01
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      • 2012-09-14
      相关资源
      最近更新 更多