Моя цель - иметь возможность тестировать маршруты с помощью приложения Flask test_client, используя self.client.post(url, ...
. Проблема, с которой я сталкиваюсь, заключается в том, что каждый раз, когда я делаю запрос, используя его, я нажимаю на DetachedInstanceError из SQLAlchemy, говоря, что не может быть выполнена операция обновления или отложенной загрузки.
Вот мои настройки:
class BaseTestCase(unittest.TestCase):
def setUp(self):
self.postgresql = Postgresql()
config = {
'FLASK_ENV': 'test',
'SQLALCHEMY_DATABASE_URI': self.postgresql.url()
}
with patch.dict('os.environ', config):
self.app = create_app()
self.client = self.app.test_client()
ctx = self.app.app_context()
ctx.push()
db.create_all()
self.assertEqual(app.testing, True)
reset_fake_data()
def tearDown(self):
db.session.remove()
self.postgresql.stop()
def post(self, url, data={}, headers={}):
headers = {'Content-Type': 'application/json', **headers}
return self.client.post(url, headers=headers, data=json.dumps(data))
def post_with_auth_token(self, url, data={}, headers={}):
headers = {'Authorization': f'Bearer {self.auth_token}'}
return self.post(url, headers=headers, data=data)
Затем в другом файле я вызываю это с response = self.post('/api/users/register', data=data)
и получаю ошибку:
sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <User at 0x10ea43f98> is not bound to a Session; lazy load operation of attribute 'courses' cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)
Ниже маршрут. Я создаю объект пользователя и затем пытаюсь добавить к нему курс, но, по-видимому, когда я пытаюсь сделать user.courses.append
, он не может лениво загрузить курсы. Я смотрел на отключение атрибута expire_on_commit
, но я не уверен, как это сделать только в случаях тестирования или если есть лучший способ сделать это.
Я читал, что преобразование из отложенной загрузки в активную может также исправить это, но я бы предпочел сохранять загрузку в отложенном режиме, и это, похоже, не исправляло это, когда я в любом случае установил соотношение lazy='subquery'
.
@users.route('/register', methods=['POST'])
def register():
data = request.get_json()
try:
user = User.from_data(**data)
except UnprocessableEntity:
return jsonify(msg='Missing parameters'), 422
except Conflict:
return jsonify(msg='Email already exists'), 409
except Unauthorized:
return jsonify(msg='Unauthorized'), 401
if data.get('invitation_token'):
invite = CourseInvite.query.filter_by(token=data['invitation_token']).first_or_404('Invite not found')
if invite.email and invite.email != user.email:
return jsonify(msg='Email mismatch'), 401
elif invite.used:
return jsonify(msg='Invite already used'), 401
user.courses.append(CourseEnrollment(course_id=invite.course.id))
invite.used = True
db.session.add(user)
db.session.commit()
return jsonify(msg='User successfully created'), 201