仅通过 API 获取唯一约束的 peewee IntegrityError
Getting peewee IntegrityError for unique constraint only through API
尝试使用 peeweee 更新我的 PostgreSQL 数据库上的记录时出现 IntegrityError。但是,它只在我尝试 HTTP PUT 方法时发生。
使用 Flask 和 Flask-Restful 创建 API 资源。 GET、DELETE 到单个博客 Post 完美运行。 Post 桶工作得很好
我可以通过 REPL 运行 完全相同的代码,它工作得很好。更奇怪的是 API 突然有点坏了,我昨天测试了这个功能,没问题。现在我无法确定发生了什么变化。
这是我在 models.py
中的 peewee 模型
class BlogPost(Model):
title = CharField(default='', unique=True)
content = TextField(default='')
created = DateTimeField(default=datetime.datetime.now)
class Meta:
database = DATABASE
这是 resources.blogposts.py
中单个博客Post 的资源
class BlogPost(Resource):
def __init__(self):
self.reqparse = reqparse.RequestParser()
self.reqparse.add_argument(
'title',
required=False,
help='No title provided',
location=['form', 'json']
)
self.reqparse.add_argument(
'content',
required=False,
nullable=True,
location=['form', 'json'],
default=''
)
super().__init__()
@marshal_with(blogpost_fields)
def get(self, id):
return (blogpost_or_404(id))
@marshal_with(blogpost_fields)
@auth.login_required
def put(self, id):
args = self.reqparse.parse_args()
try:
blogpost = models.BlogPost.get(models.BlogPost.id==id)
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.update(**args)
query.execute()
blogpost = (blogpost_or_404(id))
return (blogpost, 200, {
'Location': url_for('resources.blogposts.blogpost', id=id)
})
@auth.login_required
def delete(self, id):
try:
blogpost = models.BlogPost.select().where(
models.BlogPost.id==id
).get()
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.delete().where(models.BlogPost.id==id)
query.execute()
return '', 204, {'Location': url_for('resources.blogposts.blogposts')}
blogposts_api = Blueprint('resources.blogposts', __name__)
api = Api(blogposts_api)
api.add_resource(
BlogPost,
'api/v1/blogposts/<int:id>',
endpoint='blogpost'
)
如果我对 http://localhost:8000/api/v1/blogposts/8 执行 GET,我会在 table 中获得我唯一的博客Post(为了测试,我删除了除此之外的所有博客)
{
"id": 8,
"title": "Test3",
"content": "This is to test changes to BlogPost 1",
"created": "Wed, 19 Jun 2019 12:44:31 -0000"
}
但是,如果我 PUT 到相同的 URL,我会得到一个唯一约束。我绝对没有这个标题的数据库条目。
{
"title": "9sdnfsudngfisdngondasgjns",
"content": "lkbksigsndignsoidugnlis",
}
我可以在 REPL 中执行此操作并且它工作得很好,它应该与我在上面所做的完全相同:
blogpost = models.BlogPost.get(models.BlogPost.id==8)
blogpost.update(
title="9sdnfsudngfisdngondasgjns",
content="lkbksigsndignsoidugnlis"
)
blogpost.execute()
实际错误:
peewee.IntegrityError:重复的键值违反了唯一约束"blogpost_title" 详细信息:键(标题)=(9sdnfsudngfisdngondasgjns)已经存在。
编辑:在 peewee 错误 psycopg2 也抛出此错误之前:
UniqueViolation:重复键值违反唯一约束 "user_username_key"
详细信息:密钥(用户名)=(9sdnfsudngfisdngondasgjns)已经存在。
这真的很奇怪,但我想通了。我必须将我的 put 方法更新为与 delete 方法相同的语法。基本上,我必须将上下文传递给实际的更新方法:
@marshal_with(blogpost_fields)
@auth.login_required
def put(self, id):
args = self.reqparse.parse_args()
try:
blogpost = models.BlogPost.select().where(
models.BlogPost.id==id).get()
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.update(**args).where(models.BlogPost.id==id)
query.execute()
blogpost = (blogpost_or_404(id))
return (blogpost, 200, {
'Location': url_for('resources.blogposts.blogpost', id=id)
})
@auth.login_required
def delete(self, id):
try:
blogpost = models.BlogPost.select().where(
models.BlogPost.id==id).get()
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.delete().where(models.BlogPost.id==id)
query.execute()
return '', 204, {'Location': url_for('resources.blogposts.blogposts')}
尝试使用 peeweee 更新我的 PostgreSQL 数据库上的记录时出现 IntegrityError。但是,它只在我尝试 HTTP PUT 方法时发生。
使用 Flask 和 Flask-Restful 创建 API 资源。 GET、DELETE 到单个博客 Post 完美运行。 Post 桶工作得很好
我可以通过 REPL 运行 完全相同的代码,它工作得很好。更奇怪的是 API 突然有点坏了,我昨天测试了这个功能,没问题。现在我无法确定发生了什么变化。
这是我在 models.py
中的 peewee 模型
class BlogPost(Model):
title = CharField(default='', unique=True)
content = TextField(default='')
created = DateTimeField(default=datetime.datetime.now)
class Meta:
database = DATABASE
这是 resources.blogposts.py
中单个博客Post 的资源
class BlogPost(Resource):
def __init__(self):
self.reqparse = reqparse.RequestParser()
self.reqparse.add_argument(
'title',
required=False,
help='No title provided',
location=['form', 'json']
)
self.reqparse.add_argument(
'content',
required=False,
nullable=True,
location=['form', 'json'],
default=''
)
super().__init__()
@marshal_with(blogpost_fields)
def get(self, id):
return (blogpost_or_404(id))
@marshal_with(blogpost_fields)
@auth.login_required
def put(self, id):
args = self.reqparse.parse_args()
try:
blogpost = models.BlogPost.get(models.BlogPost.id==id)
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.update(**args)
query.execute()
blogpost = (blogpost_or_404(id))
return (blogpost, 200, {
'Location': url_for('resources.blogposts.blogpost', id=id)
})
@auth.login_required
def delete(self, id):
try:
blogpost = models.BlogPost.select().where(
models.BlogPost.id==id
).get()
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.delete().where(models.BlogPost.id==id)
query.execute()
return '', 204, {'Location': url_for('resources.blogposts.blogposts')}
blogposts_api = Blueprint('resources.blogposts', __name__)
api = Api(blogposts_api)
api.add_resource(
BlogPost,
'api/v1/blogposts/<int:id>',
endpoint='blogpost'
)
如果我对 http://localhost:8000/api/v1/blogposts/8 执行 GET,我会在 table 中获得我唯一的博客Post(为了测试,我删除了除此之外的所有博客)
{
"id": 8,
"title": "Test3",
"content": "This is to test changes to BlogPost 1",
"created": "Wed, 19 Jun 2019 12:44:31 -0000"
}
但是,如果我 PUT 到相同的 URL,我会得到一个唯一约束。我绝对没有这个标题的数据库条目。
{
"title": "9sdnfsudngfisdngondasgjns",
"content": "lkbksigsndignsoidugnlis",
}
我可以在 REPL 中执行此操作并且它工作得很好,它应该与我在上面所做的完全相同:
blogpost = models.BlogPost.get(models.BlogPost.id==8)
blogpost.update(
title="9sdnfsudngfisdngondasgjns",
content="lkbksigsndignsoidugnlis"
)
blogpost.execute()
实际错误:
peewee.IntegrityError:重复的键值违反了唯一约束"blogpost_title" 详细信息:键(标题)=(9sdnfsudngfisdngondasgjns)已经存在。
编辑:在 peewee 错误 psycopg2 也抛出此错误之前:
UniqueViolation:重复键值违反唯一约束 "user_username_key" 详细信息:密钥(用户名)=(9sdnfsudngfisdngondasgjns)已经存在。
这真的很奇怪,但我想通了。我必须将我的 put 方法更新为与 delete 方法相同的语法。基本上,我必须将上下文传递给实际的更新方法:
@marshal_with(blogpost_fields)
@auth.login_required
def put(self, id):
args = self.reqparse.parse_args()
try:
blogpost = models.BlogPost.select().where(
models.BlogPost.id==id).get()
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.update(**args).where(models.BlogPost.id==id)
query.execute()
blogpost = (blogpost_or_404(id))
return (blogpost, 200, {
'Location': url_for('resources.blogposts.blogpost', id=id)
})
@auth.login_required
def delete(self, id):
try:
blogpost = models.BlogPost.select().where(
models.BlogPost.id==id).get()
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.delete().where(models.BlogPost.id==id)
query.execute()
return '', 204, {'Location': url_for('resources.blogposts.blogposts')}