这是我第一次尝试设计Web应用程序。我为SQLAlchemy数据库创建了一个CRUD操作API。我现在正在尝试使用Pyramid设计一个RESTful Web框架来支持这个DB及其所有实体。
我一直在努力研究如何进行PUT(更新)。我知道我还需要纳入某些条件(例如Code 202)。我不确定如何使用PUT处理对象替换。视图配置中的方法有点令人困惑,我相信我正在遵循db CRUD操作。
其次,我认为必须通过{id}
查找所有资源。我相信我在get_user
方法中有这个正确的。 User_id
在db
中保存用户的所有信息...因此,如果user
查找了id
,那么我不需要全部其他信息(见delete_user
方法)。
我在设计tutorials设计时已经阅读了一些漂亮的RESTful,但鉴于我是自学成才,我仍在苦苦挣扎。真的很感谢您的帮助!
_ init _.py(URIs):
config.add_route('post_user', '/users') # POST (HTTP) / CREATE (CRUD)
config.add_route('get_user', '/users/{id}') #GET (HTTP) / RETRIEVE (CRUD)
config.add_route('put_user', '/users/{id}') # PUT (HTTP) / UPDATE (CRUD)
config.add_route('delete_user', '/users/{id}') # DELETE (HTTP) / DELETE (CRUD)
views.py(查看配置 - RESTful):
@view_defaults(renderer='json')
class RESTView(object):
api = ConvenienceAPI() # CRUD API for database
def __init__(self, request):
self.request = request
@view_config(route_name='get_user', request_method='GET')
def get_user(self):
user_id = int(request.matchdict['user_id'])
user = api.retrieve_user('user_id')
if user is None:
raise HTTPNotFound()
else:
return user
@view_config(route_name='post_user', request_method='POST')
def post_user(self):
username = request.matchdict['username']
password = request.matchdict['password']
firstname = request.matchdict['firstname']
lastname = request.matchdict['lastname']
email = request.matchdict['email']
new_user = api.create_user('username', 'password', 'firstname', 'lastname', 'email')
return Response{'new_user': user}
@view_config(route_name='put_user', request_method='PUT')
def put_user(self):
user = request.matchdict['user_id']
new_username = # is this pointing to another URL ????
updated_user = api.update_user('username', 'new_username')
return Response{status='202 Accepted'}
@view_config(route_name='delete_user', request_method='DELETE')
def delete_user(self):
user = request.matchdict['user_id']
del_user = api.delete_user('username', 'firstname', 'lastname')
return Response{'del_user': user}
答案 0 :(得分:7)
TLDR:你有很多问题。也许花更多时间学习python,然后查看金字塔和REST上的一些博客文章,如http://www.vargascarlos.com/2013/02/pyramid-and-rest/或http://codelike.com/blog/2014/04/27/a-rest-api-with-python-and-pyramid/
您的代码存在一些问题,我将首先解决。然后我会提供一些建议,以便更好地安排你的观点。
1)您在路线配置中使用了{id}
,因此您可以通过request.matchdict['id']
而非request.matchdict['user_id']
访问此内容。
额外提示:如果您想强制ID仅为数字,则可以使用{id:\d+}
。结肠后的部分是正则表达式。这应该有助于防止SQL注入。
2)您的视图已定义为使用JSON渲染器。这意味着你的视图函数应该返回一个python对象(list,dict等),然后金字塔会将这个对象提供给JSON渲染器,它会随意使用数据并创建一个响应(在这种情况下,转换它)进入有效的json。对于模板渲染器,它将使用模板中的对象)。因此,您不需要return Response{}
,而只需return {}
。如果您没有定义渲染器,那么您的视图必须自己制作并返回响应。
3)在get_user
等类方法中,您需要使用self.request访问请求,因为您已将请求保存到__init__
中的类。
4)我认为你是python的新手。例如,在post_user
中,您已使用行username = request.matchdict['username']
(应为username = self.request.params['username']
)将用户名保存到变量用户名中。通过new_user = api.create_user('username', ...
调用您的API后,您传入了一个包含内容' username'的字符串,因此您创建了一个名为' username'的用户。您实际上想要传递变量username
,例如new_user = api.create_user(username, ...
。
5)继#5之后,python中的dicts是key:value
。因此,在post_user
中,如果您想要在密钥'用户'下的json中返回新用户,那么您实际上需要return {'user': new_user}
。
所以现在我的主要建议是:你不需要为每个get / post / etc路由定义一个命名路由,你可以定义1个路由,然后利用view predicates来运行正确的函数
您可能还想创建一个ConvenienceAPI()
对象,然后共享它(完全取决于该对象正在做什么以及它是如何运行的)。您甚至可以将其附加到请求中。
您还应该考虑重用尽可能多的代码块(即我包含的get_user
函数)。
接下来的所有内容之后,以下是您的代码的样子;
config.add_route('users', '/users')
config.add_route('user', '/users/{id:\d+}')
API = ConvenienceAPI()
@view_defaults(route_name='users', renderer='json')
class UsersViews(object):
api = API
def __init__(self, request):
self.request = request
@view_config(request_method='GET')
def get(self):
users = self.api.retrieve_users()
return users
@view_config(request_method='POST')
def post(self):
username = self.request.POST.get('username')
password = self.request.POST.get('password')
firstname = self.request.POST.get('firstname')
lastname = self.request.POST.get('lastname')
email = self.request.POST.get('email')
user = self.api.create_user(username, password, firstname, lastname, email)
return user
@view_defaults(route_name='user', renderer='json')
class UserViews(object):
api = API
def __init__(self, request):
self.request = request
def get_user(self):
user_id = int(self.request.matchdict['id'])
user = self.api.retrieve_user(user_id)
return user
@view_config(request_method='GET')
def get(self):
user = self.get_user()
if user is None:
raise HTTPNotFound()
return user
@view_config(request_method='PUT')
def put(self):
user = self.get_user()
if user is None:
raise HTTPNotFound()
new_username = self.request.POST.get('username')
updated_user = self.api.update_user(user.username, new_username) # This is a strange way of updating the username, but your 'API' is not really relevant to this question.
return HTTPAccepted() # Some REST services return the updated user.
@view_config(request_method='DELETE')
def delete(self):
user = self.get_user()
del_user = self.api.delete_user(user.username, user.firstname, user.lastname)
if del_user: # If user was deleted.
return HTTPAccepted() # Or something like this. As above, you might want to return the deleted user.
else:
return HTTPBadRequest()