完全披露:Cross发布到Tastypie Google Group
我遇到的情况是我对发送到api的内容的控制有限。基本上,我需要两个Web服务才能接受来自的POST数据。两者都使用普通的POST操作和urlencoded数据(基本表单提交)。
用“卷曲”术语来思考它就像:
curl --data "id=1&foo=2" http://path/to/api
我的问题是我无法使用POST更新记录。所以我需要调整模型资源(我相信),这样如果指定了ID,POST就会充当PUT而不是POST。
class urlencodeSerializer(Serializer):
formats = ['json', 'jsonp', 'xml', 'yaml', 'html', 'plist', 'urlencoded']
content_types = {
'json': 'application/json',
'jsonp': 'text/javascript',
'xml': 'application/xml',
'yaml': 'text/yaml',
'html': 'text/html',
'plist': 'application/x-plist',
'urlencoded': 'application/x-www-form-urlencoded',
}
# cheating
def to_urlencoded(self,content):
pass
# this comes from an old patch on github, it was never implemented
def from_urlencoded(self, data,options=None):
""" handles basic formencoded url posts """
qs = dict((k, v if len(v)>1 else v[0] )
for k, v in urlparse.parse_qs(data).iteritems())
return qs
class FooResource(ModelResource):
class Meta:
queryset = Foo.objects.all() # "id" = models.AutoField(primary_key=True)
resource_name = 'foo'
authorization = Authorization() # only temporary, I know.
serializer = urlencodeSerializer()
foo_resource = FooResource
...
url(r'^api/',include(foo_resource.urls)),
)
在Freenode上的#tastypie中,Ghost []建议我通过在模型资源中创建一个函数来覆盖post_list(),但是,我还没有成功使用它。
def post_list(self, request, **kwargs):
if request.POST.get('id'):
return self.put_detail(request,**kwargs)
else:
return super(YourResource, self).post_list(request,**kwargs)
不幸的是,这种方法对我不起作用。我希望更大的社区可以为这个问题提供一些指导或解决方案。
注意:我无法覆盖来自客户端的标头(根据:http://django-tastypie.readthedocs.org/en/latest/resources.html#using-put-delete-patch-in-unsupported-places)
答案 0 :(得分:1)
我在用户创建方面遇到了类似的问题,我无法检查记录是否已存在。我最终创建了一个自定义验证方法,该方法验证用户是否不存在,在哪种情况下帖子可以正常工作。如果用户确实存在,我从验证方法更新了记录。 api仍然返回400响应,但记录已更新。感觉有点hacky但是......
答案 1 :(得分:1)
from tastypie.validation import Validation
class MyValidation(Validation):
def is_valid(self, bundle, request=None):
errors = {}
#if this dict is empty validation passes.
my_foo = foo.objects.filter(id=1)
if not len(my_foo) == 0: #if object exists
foo[0].foo = 'bar' #so existing object updated
errors['status'] = 'object updated' #this will be returned in the api response
return errors
#so errors is empty if object does not exist and validation passes. Otherwise object
#updated and response notifies you of this
class FooResource(ModelResource):
class Meta:
queryset = Foo.objects.all() # "id" = models.AutoField(primary_key=True)
validation = MyValidation()
答案 2 :(得分:0)
根据Cathal的建议,我能够利用验证功能更新我需要的记录。虽然这不会返回有效的代码......但它有效。
from tastypie.validation import Validation
import string # wrapping in int() doesn't work
class Validator(Validation):
def __init__(self,**kwargs):
pass
def is_valid(self,bundle,request=None):
if string.atoi(bundle.data['id']) in Foo.objects.values_list('id',flat=True):
# ... update code here
else:
return {}
确保在validation = Validator()
元数据中指定ModelResource
。