How to insert POST data into Django model using rest-frameWork - python

I am trying to POST data to my Django app using Django rest-frameWork...
My view is :
#csrf_view_exempt
class subscriptionsList(APIView):
def post(self, request, format=None):
key = self.request.QUERY_PARAMS.get('appKey', None)
keyData = app.objects.filter(appKey=key).exists()
if keyData == True:
serializer = PostSubscriptionDetailSerializer(data=request.DATA)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
urls.py :
url(r'^subscribe/$',subscriptionsList,name='subscriptions-list'),
serializer.py
class PostSubscriptionDetailSerializer(serializers.ModelSerializer):
class Meta:
model = subscriptions
fields = ('subAppName','subStoreName','subTagName','emailID')
Can someone tell me how to POST data using Django REST-frameWork...

Related

Getting error in .is_valid() method in DRF

I am tyring to create a User Registration API, but I am getting an error when using a POST request in the following view:
#action(methods=['GET', 'POST'], detail=False, permission_classes=[AllowAny])
def users(self, request):
if request.method == 'GET':
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data, status=status.HTTP_201_CREATED)
elif request.method == 'POST':
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
if serializer.available():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
The exception returned is the following:
Cannot call `.is_valid()` as no `data=` keyword argument was passed when
instantiating the serializer instance.
You pass an object or a queryset to a serializer when you want to serialize it, so it's fine in your GET method.
However, when you want to create an object using a serializer, you have to pass the data parameter before calling .is_valid(), and only then you can create your new objects withsave(). This is because the serializer needs to validate the data given to him before he does any save.
What you should do is the following:
[...]
elif request.method == 'POST':
serializer = UserSerializer(data=request.data, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

DRF Response isn't working with class based views in Django

I am converting my function-based views to class-based views. Following the official documentation, I was getting errors using the Response imported from rest_framework. When using HttpResponse it's working fine. The error I am getting with Response is:
.accepted_renderer not set on Response
This is my view:
def get(self, request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
What could be the reason for this?
serializer:
class Meta:
model = User
fields = '__all__'
instead of this:
return Response(serializer.data)
try this:
return Response(serializer.data, status=status.HTTP_200_OK) #Status is depends on your code
I think your serializer is not saved so that's why you are getting that error
def get(self, request):
users = User.objects.all()
serializer = UserSerializer(users, data=request.data, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Final thing try this.

How can I send images from Django Rest Api to a Vue SPA?

I am developing a Vue.js 2.0 single page application with DRF REST api on the backend. I have images stored in filesystem and one of my models has a field called "image" containing the address of the image.
My model:
class Board(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=400)
image = models.FileField(upload_to='boards/')
safe_for_work = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
Viewset:
class BoardViewSet(viewsets.ViewSet):
serializer_class = BoardSerializer
def list(self, request,):
queryset = Board.objects.filter()
serializer = BoardSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = Board.objects.filter()
board = get_object_or_404(queryset, pk=pk)
serializer = BoardSerializer(board)
return Response(serializer.data)
When i call my endpoint from my Vue SPA, instead of getting the image, I only get the local url, for example "/storage/boards/board1.jpg".
How can I access the actual image on my Vue page?
Ideally I would like to get a list of all the images from the endpoint and display them.
With this issue you must config in server (Django Rest) instead of Vue client. Config your serializer to display full path of image:
class BoardSerializer(ModelViewSet)
image = FileField(source='image')
class Meta:
model = Article
fields = [
'id',
'image',
...
]
Don't forget context: { 'request': request } in Viewset
def list(self, request,):
queryset = Board.objects.filter()
serializer = BoardSerializer(queryset, many=True, context: { 'request': request })
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = Board.objects.filter()
board = get_object_or_404(queryset, pk=pk)
serializer = BoardSerializer(board, context: { 'request': request })
return Response(serializer.data)
Hope it helps!

How can I return the created data when created success in Django

In my Django project, I have a APIView:
class PhysicalServerManualGenerateOrderAPIView(CreateAPIView):
serializer_class = PhysicalServerManualGenerateOrderSerialzier
permission_classes = [IsFinanceAdmin, IsSuperAdmin]
queryset = Order.objects.all()
in the PhysicalServerManualGenerateOrderSerialzier:
class PhysicalServerManualGenerateOrderSerialzier(ModelSerializer):
...
def create(self, validated_data):
try:
order = getOrder(user=user, validated_data=validated_data) # there I create the order instance
except Exception as e:
order = None
return order
But I have a requirement, I want to return the created order's id (or other data) when I access the APIView success.
Change your api as below,
from rest_framework.response import Response
from rest_framework import status
class PhysicalServerManualGenerateOrderAPIView(CreateAPIView):
# your code
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
sufficent_data = serializer.data # you will get the serialized data here, which includes the "order_id" too
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
When you call the self.perform_create(serializer) the create() method of PhysicalServerManualGenerateOrderSerialzier class will get called and return the Order instance. serializer.data will serialize that instance and makes it available at API class

Multiple nested resources with multiple methods are not displayed in Django Rest Framework Documentation

I wonder why Django REST Framework build-in documentation doesn't display methods for a User. I have only available list, create, read, update for these URLs:
url(r'^users$', views.UserList.as_view()),
url(r'^users/(?P<user_id>\w+)$', views.UserDetail.as_view()),
views.py:
#permission_classes([CustomPermission])
class UserList(GenericAPIView):
"""
get: Return all users.
post: Create a user.
"""
serializer_class = UserSerializer
def get(self, request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#permission_classes([UserPermission])
class UserDetail(GenericAPIView):
"""
get: Return user by ID.
put: Update user by ID.
delete: Delete user by ID.
"""
serializer_class = UserSerializer
def get(self, request, user_id):
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = UserSerializer(user)
return Response(serializer.data)
def put(self, request, user_id):
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = UserSerializer(user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, user_id):
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
However example shown below is not visible in build-in documentation. I have also Swagger documentation in the project and everything is displayed properly.
urls.py:
url(r'^users/(?P<user_id>[0-9]+)/object$', views.UserObject.as_view()),
views.py:
#permission_classes([UserPermission])
class UserObject(GenericAPIView):
"""
post: Create a user object by his ID.
get: Return a user object by his ID.
put: Update a user object by his ID.
delete: Delete a user object by his ID.
"""
serializer_class = ObjectSerializer
def post(self, request, user_id):
try:
Object.objects.get(user=user_id)
return Response(status=status.HTTP_403_FORBIDDEN)
except Object.DoesNotExist:
serializer = ObjectSerializer(data=request.data)
serializer.fields['user'].required = False
if serializer.is_valid():
serializer.save(user_id=user_id)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get(self, request, user_id):
try:
object = Object.objects.get(user=user_id)
except Object.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = ObjectSerializer(object)
return Response(serializer.data)
def put(self, request, user_id):
try:
object = Object.objects.get(user=user_id)
except Object.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = ObjectSerializer(object, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, user_id):
try:
object = Object.objects.get(user=user_id)
except Object.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
object.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
There should be visible path users/{user_id}/object Any idea why is not?
Edit 2017-08-19
I've made a PR with the fix which has already been merged. So may be try to get latest version.
Edit 2017-08-13
This is a bug with DRF default documentations, where extra actions with more than one method are not displayed in the docs.
Solution: use swagger
Original
I tried reproducing it, looks like there is a bug in the coreapi from django-rest-framework.
I've tried with the doc generator swagger for rest-framework and it looks fine.
There is a bug in the url if you remove object from users/{user_id}/object it works. If you try for example xsers/{user_id}/ it'll work.
You could change the design approach using a ViewSet.
ViewSet provides actions instead of mapping directly to the method. It's another level of abstraction, usually clearer.
class UserViewSet(viewsets.ViewSet):
"""
retrieve:
Return the given user.
list:
Return a list of all the existing users.
create:
Create a new user instance.
update:
Update a user.
"""
serializer_class = UserSerializer
def list(self, request):
# Here you should put the code for GET user/
pass
def create(self, request):
# Here you should put the code for POST user/
pass
def retrieve(self, request, pk=None):
# Here you should put the code for RETRIEVE user/{pk}
pass
def update(self, request, pk=None):
# Here you should put the code for UPDATE user/{pk}
pass
#detail_route(methods=['get'])
def objects(self, request, pk=None):
if request.method == 'GET'
....
And in your urls
from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = router.urls
More info http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing

Categories

Resources