1

完全開示:TastypieGoogleGroupにクロス投稿

APIに送信される内容を制御するのが制限されている状況があります。基本的に、POSTデータを受け入れることができるようにする必要がある2つのWebサービスがあります。どちらも、urlencodedデータでプレーンなPOSTアクションを使用します(基本的に基本的なフォーム送信)。

「カール」の用語で考えると、次のようになります。

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

私の問題は、POSTを使用してレコードを更新できないことです。したがって、IDが指定されている場合、POSTがPOSTではなくPUTとして機能するように、モデルリソースを調整する必要があります(私は信じています)。

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

urls.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

ユーザーの作成時に同様の問題があり、レコードが既に存在するかどうかを確認できませんでした。ユーザーが存在しない場合に検証するカスタム検証メソッドを作成することになりました。その場合、投稿は正常に機能します。ユーザーが存在した場合、検証メソッドからレコードを更新しました。API は引き続き 400 応答を返しますが、レコードは更新されます。少しハックな感じですが...

于 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 に答える