1

全面披露:交叉发布到 Tastypie Google Group

我有一种情况,我对发送到我的 api 的内容的控制有限。本质上,我需要能够接受来自的 POST 数据的两个 Web 服务。两者都使用带有 urlencoded 数据的普通 POST 操作(本质上是基本表单提交)。

用“卷曲”术语思考它就像:

curl --data "id=1&foo=2" http://path/to/api

我的问题是我无法使用 POST 更新记录。所以我需要调整模型资源(我相信),这样如果指定了 ID,则 POST 充当 PUT 而不是 POST。

api.py

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()

网址.py

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 )

4

3 回答 3

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()
于 2013-03-01T10:46:36.830 回答
1

我在创建用户时遇到了类似的问题,我无法检查记录是否已经存在。我最终创建了一个自定义验证方法,该方法验证用户是否不存在,在这种情况下,post 可以正常工作。如果用户确实存在,我会从验证方法更新记录。api 仍然返回 400 响应,但记录已更新。感觉有点hacky但是...

于 2013-02-28T17:13:35.787 回答
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元数据中指定。

于 2013-03-01T09:02:44.630 回答