我想用Falcon创建一个简单的应用程序,它能够处理带有hostname
:ip
记录的小型sqlite数据库。我希望能够替换 sqlite 中的行,所以我决定hostname
是唯一字段。我有一个model.py
:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine, Column, Integer, String
Base = declarative_base()
DB_URI = 'sqlite:///clients.db'
class Client(Base):
__tablename__ = 'clients'
id = Column(Integer, primary_key=True)
hostname = Column(String(50), unique=True)
ip = Column(String(50))
我的简单resources.py
:
from falcon_autocrud.resource import CollectionResource, SingleResource
from models import *
class ClientCollectionResource(CollectionResource):
model = Client
methods = ['GET', 'POST']
当我使用有关hostname
的更新信息发出 POST 请求时:ip
出现Unique constraint violated
错误:
req = requests.post('http://localhost:8000/clients',
headers={'Content-Type': 'application/json'},
data=json.dumps({'hostname': 'laptop1', 'ip': '192.168.0.33'}));
req.content
>> b'{"title": "Conflict", "description": "Unique constraint violated"}'
有没有办法使用sqlalchemy
替换现有记录?或者也许我出于这些目的选择 sqlite 是错误的?
在构建 REST-ful API 时,不应使用POST
来更新现有资源,POST
资源只应创建新资源。falcon-autocrud
在这里做正确的事情。
相反,请在单个资源(为.../clients/<identifier>
注册的SingleResource
资源)上使用PUT
来更改现有资源。
如果您在SingleResource
定义中使用hostname
,那么falcon-autocrud
应该自动使用该列作为标识符(假设您的SingleResource
子类被称为ClientResource
):
app.add_route('/clients/{hostname}', ClientResource(db_engine))
此时,您可以直接使用以下方法PUT
新的ip
值:
requests.put('http://localhost:8000/clients/laptop1', json={'ip': '192.168.0.33'})
(请注意,requests
直接支持 JSON 请求;json=
关键字参数将为您编码为 JSON,并且在您使用它时会自动为您设置Content-Type
标头)。
您可能希望限制为Client
对象返回的字段。使用唯一的hostname
您不希望通过发送主键列来混淆客户端。我会通过在资源类上设置response_fields
属性来限制响应字段:
class ClientCollectionResource(CollectionResource):
model = Client
response_fields = ['hostname', 'ip']
methods = ['GET', 'POST']
class ClientResource(SingleResource):
model = Client
response_fields = ['hostname', 'ip']
我看到falcon-autocrud
还不支持对集合PATCH
更改现有资源的请求(仅支持"op": "add"
),否则这也是更改现有条目的另一种途径。