PUT request in Tasty PIE to update using non PK value - tastypie

I am using Tasty Pie to create Services. I have applied filtering so that it searches based on non PK value:
My api.py file :
class TestResource(ModelResource):
class Meta:
queryset = ack_dadc.objects.all()
authorization = Authorization()
filtering = {
'DistributorUID': ['exact'],
}
detail_allowed_methods = ['get', 'post', 'put', 'delete']
My question is:
Can I do a PUT request based on http:localhost/api/v1/test/?DistributorUID=steve
I have googled a lot but no luck I just want to update the database based on non PK value.

You'll find an example of how to achieve this using normal URL arguments in the Tastypie Cookbook: http://django-tastypie.readthedocs.org/en/latest/cookbook.html#using-non-pk-data-for-your-urls

I don't think you can do this : filters are only applied on GET requests.
So if you want to achieve this you have to do it with 2 requests :
GET http:localhost/api/v1/test/?DistributorUID=steve
to get the ID of the resource and then
PUT http:localhost/api/v1/test/ID
to update it based on its ID.

Related

RESTFUL URLS in rails?

Hi I'm building REST api for an app, I have a requirement in URL
such that url should be something like this e.g
www.abc.com/api/param1/value1/param2/value2/param3/value3.... and so on
There are cases
case: The number of params are not limited it can change frequent
if today it is something like this
www.abc.com/api/param1/value1/param2/value2/param3/value3
tomorrow it can be like this
www.abc.com/api/param1/value1/param2/value2/param3/value3/param4/value4
Is there a configuration where once you configure the url pattern
and every thing go smooth
and in conrtoller params should contain this kind of key-value pair
{ "param1" => "value1","param2" => "value2","param3" => "value3"...and so on }
any suggestion !! how to achieve this ??
If your params are not fixed you can use wildcard in routing
for e.g
get 'items/list/*specs', controller: 'items', action: 'list'
def list
specs = params[:specs] # e.g, "base/books/fiction/dickens" #split it and place in a hash
end
Rails routing provides a way to specify fully custom routes with static and dynamic segments as explained in the Rails Routing Guide.
Your requirement should be achievable with
get '/api/param1/:param1/param2/:param2/...', to: 'controller#action'
You can use route scoping for this particular kind of problem . In other way it is nested routes
More details : http://guides.rubyonrails.org/routing.html#nested-resources
This is a example,
GET /magazines/:magazine_id/ads/:id/edit ads#edit
return an HTML form for editing an ad belonging to a specific magazine
I think this would be helpful for you.

Django Rest Framework - business action specific views?

I have a basic model based view that uses a model serializer:
class ActionItemTextSerializer(serializers.ModelSerializer):
assignee_name = serializers.CharField(source='get_assignee_name')
class Meta:
model = ActionItem
fields = ('id', 'created_by', 'created_date', 'project', 'portfolio', 'name', 'description', 'parent', 'priority', 'status', 'assignee', 'assignee_name', 'wf_get_actions')
#depth = 1
class ActionItemViewSet(viewsets.ModelViewSet):
queryset = ActionItem.objects.all()
serializer_class = ActionItemTextSerializer
So when I go to /actionitems/ I get a list of them and when I go to /actionitems/5/ I will get details for an individual action item.
My action items can have specific actions associated with them - how do I go about extending all this to have the following:
GET /actionitems/5/assign and get model view for action item with id=5 but with additional data (I can add this via view's serializer I suppose)
PUT /actionitems/5/assign and trigger a view that will update the model data with PUT data and do an additional change to it based on the action key ('assign') passed to it?
Can I somehow extend the ModelViewSet so that it can return different serializer and perform different actions while PUT/POST etc based on the parameter after the /actionitems/5/? Or should I use a different approach here.
Django REST framework allows you to add "actions" to a ViewSet through the #detail_route decorator. You can read more about the decorator in the documentation for ViewSets and it requires the use of the built-in routers.
In order to support multiple request methods (PUT/POST), you are going to need to pass them in through the methods argument to the decorator. So you would be using
#detail_route(methods=['post', 'put'])
You can then route based on the method that is being used by checking request.method on the request that is passed in.

Symfony2 Form Rest Api only add to Relation

I am using Symfony2 as Rest Api for a JS Frontend App. I came across a scenario where I want users to "invite" (=add) Users to a Group. But I want to only allow them to add Users to the existing Relation and not "overwrite" the whole relation, which is the standard behaviour in combination with a regular Symfony2 Form.
What would be the best practice to achieve this behaviour?
Additional Comment:
I am using Ember-Data in the frontend and my frontend would probably send a put request with the whole Group including additional users (but not all).
My JSON Payload would look something like this:
{
"usergroup": {
"name":"yxcv2",
"stake":"sdfghj",
"imageName":null,
"userCount":5,
"users":[
5,
6,
7
],
"gameGroup":"13",
}
}
In this scenario User 1,2,3 and 4 are already members of the group. And instead of replacing 1,2,3,4 with 5,6,7, I want to ADD 5,6,7 to the already existing members.
A LINK request should be used to add an item to an existing collection instead of overwriting it with a POST request.
Using a symfony form you'd post the User (id) plus a hidden field _method with value LINK to something like /groups/{id}.
routing would be something like this:
group_invite:
path: /groups/{id}
defaults: { _controller: YourBundle:Group:inviteUser }
methods: [LINK]
You could use FOSRestBundle's implicit resource name definition, too.
For the method override to work the config setting framework.http_method_override needs to be set to true ( = default value - available since symfony version 2.3).
More information can be found in the documentation chapter:
How to use HTTP Methods beyond GET and POST in Routes

Tastypie PUT : partial update on all objects in a resource

I have a django model like this, (BTW: I am using Tastypie)
class Watchlist(models.Model):
name = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey('users.User')
stocks = models.ManyToManyField('Stock')
equityboss = models.BooleanField(blank=True, default=False)
last_watched = models.DateTimeField(auto_now_add=True)
order = models.IntegerField(max_length=10)
I want to update order field alone for all the objects in watchlist model.
I tried by sending PUT request, it erased all my records. I didn't get any error.
This is the data I send via PUT request
{'objects': [{'resource_uri': '/api/eboss/watchlist/2/', 'id': u'2', 'order': 0}, {'resource_uri': '/api/eboss/watchlist/1/', 'id': u'1', 'order': 1}]}
Please tell me what is the problem?
Look into HTTP PATCH (the RFC) - it's supported by Tastypie (their docs) and allows you to partially update a resource.
It looks like you will need to make individual PATCHes to each resource, however, as there is no mention of PATCHing a list in the same way you can PUT a new copy of the list.

I want an EmbeddedListField of comments to show up only when I 'GET' a single post and not when I 'GET' a list of posts

I have a mongodb document 'Post' which has EmbeddedListField of 'comments'. I'm using tastypie to build the API layer and I want the comments to be listed with their body fields only when a single post is requested. When a list of posts is requested I do not want to show the full comment body as this would kill my app's performance. This is what I have in my resource file:
comments = tastypie_mongoengine_fields.EmbeddedListField(of='api_core.resources.EmbeddedCommentResource', attribute='comments', full=True, null=True)
What can I do about this? I do not want to create two entry points for 'post_entry' and 'post_list' as this would be bad design for the consumer of the APIs.
I did a simple check in the dehydrate method:
def dehydrate(self, bundle):
if self.get_resource_uri(bundle) != bundle.request.path:
bundle.data['comments_count'] = len(bundle.data['comments'])
del bundle.data['comments']
bundle.data['user_id'] = bundle.data['user'].data['id']
bundle.data['user_name'] = bundle.data['user'].data['first_name']
bundle.data['user_uri'] = bundle.data['user'].data['resource_uri']
del bundle.data['user']
return bundle