7👍
The easiest way is to do it this way.
keep the models class the same
views.py
from rest_framework import viewsets
#impost serializer and model class for subscription
class SubscriptionViewSet(viewsets.ModelViewSet):
serializer_class = SubscriptionSerializer
def get_queryset(self):
queryset = Subscription.objects.all()
#if you need to get subscription by name
name = self.request.QUERY_PARAMS.get('name', None)
if name is not None:
queryset = queryset.filter(name=name)
return queryset
serializers.py
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields = ('name','quantity', 'stripe_id')
# django will handle get, delete,patch, update for you ....
# for customization you can use def update or def create ... to do whatever you need
# def create(self, validated_data):
# you can handle the email here
# and something like subscription= Subscription (name=validated_data['name'],vendor=validated_data['quantity']...)
# subscription.save()
# it will save whatever you want
urls.py
#use the router to handle everything for you
from django.conf.urls import patterns, include, url
from rest_framework import routers
#import your classes
router = routers.DefaultRouter()
router.register(r'subscription', views.SubscriptionViewSet,base_name='subscription')
urlpatterns = patterns('',
url(r'^', include(router.urls)),
)
3👍
For the creation of an Object you must implement the create function as described in the official documentation, found here. For patching you could use the partial argument from within you view class:
SubscriptionSerializer(subscription, data={'something': u'another', partial=True)
For deletion of the a Subscription, that could be done when you get the delete call as so in your view class:
if request.METHOD == 'DELETE':
subscription = Subscription.objects.get(pk=pk)
subscription.delete()
See this tutorial for complete example
Further more I think that you should include the “id” field in the SubscriptionSerialiser Meta class, otherwise it will be difficult to do the updates/deletions. I hope this helped a little.
Cheers,
Tobbe
- Django Apache mod_wsgi 500
- Multiple default values specified for column "id" of the table
- Django orm group by multiple columns
3👍
-
When you want to use a method that allow make these operations you have to use a @detail_route() where you can say as well which methods will you use, like in the docs is said:
@detail_route(methods=[‘post’])
def set_password(self, request, pk=None):
user = self.get_object()
serializer = PasswordSerializer(data=request.data)
…
So to be able to use them you should add the next decorator
@detail_route(methods=['post', 'patch'])
- To add another parameters you can do it for the .save() parameter. You just have to indicate the name of this and them just override your .save() model to check if that email belongs or not to the user that is trying to do the subscription. Here I paste you what the Django Rest docs says:
” Passing additional attributes to .save()
…
You can do so by including additional keyword arguments when calling .save(). For example:
serializer.save(owner=request.user)
Here I leave you the link for more information:
http://www.django-rest-framework.org/api-guide/serializers/#passing-additional-attributes-to-save
3👍
- Using the above when I send a PATCH request, I get an error. How can I fix this?
Expected view SubscriptionDetail to be called with a URL keyword
argument named “pk”. Fix your URL conf, or set the .lookup_field
attribute on the view correctly.
The error is caused because unlike create
request, patch
/update
require a pk
to know which object to update. That is why you have to supply the pk
value for it. So, your url for PUT
, DELETE
andPATCH
must have at least named parameter like this –
subscription = SubscriptionDetail.as_view({
'patch': 'update'
})
url(r'^rest-auth/subscription/(?<pk>(\d+))$', subscription, name='something'),
an example url will be – rest-auth/subscription/10
where 10
is the pk
or id
of the object. Django Rest Framework will then load the object internally to be updated.
- While sending the patch request I would also like to send an ’email’ field which is not on the subscription model. Is this possible to do? I need the email field in the POST (create) operation so that I know which user the subscription belongs to.
To add custom parameters, first declare the property in serializer, it is better to keep it required=False
, so that other request does not throw error –
class SubscriptionSerializer(serializers.ModelSerializer):
custom_field = serialiers.BooleanField(required=False)
class Meta:
model = Subscription
fields = ('name','quantity', 'stripe_id')
def update(self, instance, validated_data):
print "In update"
so far this is enough for the django rest framework to accept the field custom_field
and you will find the value in update
method. To get the value pop it from the attributes supplied by the framework like this –
def update(self, instance, validated_data):
custom_field = validated_data.pop('custom_field', None)
if custom_field is not None:
# do whatever you like with the field
return super().update(instance, validated_data)
# for python < 3.0 super(SubscriptionSerializer, self).update(instance, validated_data)
- How to access user names and profiles with django-allauth
- Django-registration compatibility issue with django 1.7
- Dynamic pagination using Generic ListView
- Dynamic Django Mail Configuration
- Django Admin, accessing reverse many to many
2👍
-
When you overrided (I don’t know if that’s the proper conjugation of overriding a method) the update method, you stopped the ability to PUT or PATCH and object. Your new method only prints out “In update” but doesn’t save the instance. Look at the update method from the serializer.ModelSerializer object:
def update(self, instance, validated_data): raise_errors_on_nested_writes('update', self, validated_data) for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() return instance
Notice the last few lines where the instance is saved with the values and then returned. Remove your update method on the SubscriptionSerializer object. This let’s your parent object’s create, update, retrieve, and delete methods do their magic which supports PATCH and PUT updates. The next problem is that your urls.py is using the Django rather than the REST framework router. Change it to this:
from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r'subscription', SubscriptionDetail)
That should solve the patch update problem.
- I don’t think you can add an email field in your patch method without the attribute on the subscription model. That’s just a guess on my part, and I may be wrong. Does the email field map to anything on any object? Can you use a ForeignKey to map it?
I hope that works for you, good luck!
- Django proxy User model example
- How to add custom error codes to Django Rest Framework
- Django-admin.py startproject mysite not working well on windows 7
- Django-allauth: Only allow users from a specific google apps domain
0👍
In view.py you just need set the class with:
class SubscriptionDetail(mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
generics.GenericAPIView):
and add this to fix .lookup_field :
def update(self, request, *args, **kwargs):
log.error("OBJ update kwargs= %s , data = %s" % (kwargs, str(request.data)))
pk = request.data.get('id')
if (kwargs.get('pk') is not None):
kwargs['pk'] = request.data.get('id')
self.kwargs['pk'] = request.data.get('id')
return super().update(request, *args, **kwargs)
and add support to methods do you want :
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
# def get(self, request, *args, **kwargs):
# return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
# def patch(self, request, *args, **kwargs):
# return self.partial_update(request, *args, **kwargs)
#
# def delete(self, request, *args, **kwargs):
# return self.destroy(request, *args, **kwargs)
only tweak that remains is get for list or get for retrieve on element but should be easy now add something if we have one pk we may call self.retrieve else we may call self.list