2013-02-27 3 views
1

Полного раскрытия: Крест отправил в Tastypie Google GroupПреобразовать POST на PUT с Tastypie

У меня есть ситуации, когда я ограниченный контроль над тем, что посылаются на мой апи. По сути, есть два веб-сервиса, от которых мне нужно принять POST-данные. Оба используют простые действия POST с urlencoded данными (основная форма представления).

Думая об этом в «вьются» терминах это как:

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

urls.py

foo_resource = FooResource 

... 
url(r'^api/',include(foo_resource.urls)), 
) 

В #tastypie на Freenode, 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

Я использую метод obj_create как по этой ссылке http://stackoverflow.com/questions/10070173/tastypie-obj-create-how-to-use-newly-created-object и отлично работает –

ответ

1

У меня была аналогичная проблема на создание пользователей, где я не был в состоянии проверить, если запись уже существует. Я закончил создание специального метода проверки, который был проверен, если пользователь не существовал, и в этом случае почта будет работать нормально. Если пользователь действительно существует, я обновил запись из метода проверки. Api по-прежнему возвращает ответ 400, но запись обновляется. Он чувствует себя немного взломанным, но ...

+0

Не могли бы вы показать пример кода? –

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 мета.

+0

Да, он не возвращает действительный код. Удалось ли вам найти решение? – itsji10dra

+0

Он возвращает сбой, но на самом деле не работает. Это было мое решение. –

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