Can I use Serializer just for validation purpose?
for example if I had CommentSerializer as
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
Is it as as per motive of DRF to use this serializer just for validation of request or some data without refering to any Django models? For example:
from rest_framework.views import APIView
from rest_framework.response import Response
class MyAPIView(APIView):
def post(self, request, format=None):
serializer = CommentSerializer(data=dict(request.data))
if serializer.is_valid():
validated_data = serializer.validated_data
# do something with validated_data
# return some data as Response()
or am I fighting against the framework guidance?
Related
I am using Django Rest Framework so that my other Django project can change records in this project's database, and am using serializers to do so. I am using the .save() method, which will add to the database only if none of the existing records share the same primary key as the ones being saved. I would like to "update" these existing records, either by updating them straight or deleting them then creating them again.
This is my views.py:
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .serializers import parcelSerialiser
#api_view(['POST'])
def addItem(request):
serializer = parcelSerialiser(data=request.data, many = True)
print(request.data)
print(serializer.is_valid())
print(serializer.errors)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
and my serializers.py:
from rest_framework import serializers
from mainMenu.checkIn.models import Parcels
class parcelSerialiser(serializers.ModelSerializer):
class Meta:
model = Parcels
fields = '__all__'
It allow me to pass in json format data to post for creating record after i make def create so that json format like [{data:data,data:data}] can post in. How should i do so that i can also make put request with multiple object in one request or using post method to update?
Below is views.py.
from django.shortcuts import render
from .models import ListForm
# Create your views here.
from rest_framework import viewsets
from .serializers import ListFormSerializer
from rest_framework import filters
import django_filters.rest_framework
from rest_framework.response import Response
from rest_framework import status, viewsets
class ListFormViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = ListForm.objects.all().order_by('group')
serializer_class = ListFormSerializer
filter_backends = (django_filters.rest_framework.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,)
filterset_fields = ['group','key_description']
search_fields = ['group']
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, many=isinstance(request.data,list))
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
# return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
Maybe you need something like this:
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework.decorators import action
import json
from .models import Post
from .serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.none()
serializer_class = serializers.PostSerializer
#action(detail=False, methods=['post'])
def update_this(self, request):
try:
data = json.loads(request.data)
except:
try:
data = dict(request.data)
except:
data = request.data
# You can do everything you want here with data
return Response({'code': 0, 'desc': 'OK', 'more_data': {}})
I'm trying to create a new entry in my database with Django REST framework and I am able to successfully send a request however validated_data is empty:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.shortcuts import render
from rest_framework import viewsets
from django.shortcuts import get_object_or_404, get_list_or_404
from .models import GetPurchases, CarFax
from .serializers import PurchasesSerializer
from .serializers import CarFaxSerializer
from rest_framework.response import Response
# Create your views here.
class GetCarFax(viewsets.ModelViewSet):
''' This view will be used for POSTing new carfax reports to the database '''
queryset = CarFax.objects.all()
serializer_class = CarFaxSerializer
# authentication_classes = []
permission_classes = []
#print('TEST')
def list(self, request):
# accessed at url: ^api/v1/carfax/$
queryset = CarFax.objects.all()
serializer = CarFaxSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None, *args, **kwargs):
# accessed at url: ^api/v1/retrieve/{pk}/$
queryset = CarFax.objects.all()
record = get_list_or_404(queryset, vin__exact=pk)
serializer = CarFaxSerializer(record, many=True)
return Response(serializer.data)
def create(self, request, **validated_data):
print('TEST')
print(request.data)
print(validated_data)
serializer = CarFaxSerializer(CarFax.objects.create(**validated_data))
headers = self.get_success_headers(serializer.data)
print(serializer.data)
print(headers)
return Response(serializer.data, headers=headers)
serializers.py
class CarFaxSerializer(serializers.ModelSerializer):
class Meta:
model = CarFax
fields = ('vin', 'structural_damage', 'total_loss',
'accident', 'airbags', 'odometer', 'recalls',
'last_updated')
When I print request.data I can see the data I sent. However validated_data is empty, which is the dict I'm using to create the models.
The accepted answer is a nice refactoring but it doesn't answer the question, and thus may not help future readers (like myself, who just went through this). The real reason validated data was empty was because the when you override .create on the ModelViewSet you wipe out the serializer model field bindings and have to explicitly specify them as you would on a regular serializer.
CarFax serializer should have been defined like so:
class CarFaxSerializer(serializers.ModelSerializer):
vin = serializers.CharField(23),
structural_damage = serializers.BooleanField(),
total_loss = serializers.BooleanField(),
accident = serializers.BooleanField(),
airbags = serializers.BooleanField(),
odometer = serializers.IntegerField(),
recalls = serialziers.BooleanField(),
last_updated = serializers.DateField(),
class Meta:
model = CarFax
fields = ('vin', 'structural_damage', 'total_loss',
'accident', 'airbags', 'odometer', 'recalls',
'last_updated')
First of all, your GetCarFax class seems like messy :( because you'd override most of the methods, but it doesn't provide any advantages to the view. So change your GetCarFax view class to below,
class GetCarFax(viewsets.ModelViewSet):
"""
This view will be used for POSTing new carfax reports to the database
"""
queryset = CarFax.objects.all()
serializer_class = CarFaxSerializer
# authentication_classes = []
permission_classes = []
lookup_field = 'myfieldname'
This few lines of code will handle all the CRUD operations for you :)
I am creating a Notification apps by Django Rest Framework which users can MARK AS READ ALL notification by using PATCH API in frontend. How can I Bulk Update data can do this task.
This serializer and viewset below just for PATCH only one notification object, but I want to do it all with Notifications which have field is_read = False
Edited with the right way
My Serializers:
class NotificationEditSerializer(ModelSerializer):
class Meta:
model = Notification
fields = (
'id',
'is_read'
)
My Viewset:
from rest_framework.response import Response
class NotificationListAPIView(ReadOnlyModelViewSet):
queryset = Notification.objects.all()
permission_classes = [AllowAny]
serializer_class = NotificationEditSerializer
lookup_field = 'id'
#list_route(methods=['PATCH'])
def read_all(self, request):
qs = Notification.objects.filter(is_read=False)
qs.update(is_read=True)
serializer = self.get_serializer(qs, many=True)
return Response(serializer.data)
My URL:
from rest_framework import routers
router.register(r'notifications/read_all', NotificationListAPIView)
You can try to use list_route for example:
from rest_framework.response import Response
from rest_framework.decorators import list_route
class NotificationListAPIView(ReadOnlyModelViewSet):
#YOUR PARAMS HERE
#list_route()
def read_all(self, request):
qs = Notification.objects.filter(is_read=False)
qs.update(is_read=True)
serializer = self.get_serializer(qs, many=True)
return Response(serializer.data)
the api is available by ^YOUCURRENTURL/read_all/$ more details marking-extra-actions-for-routing
NOTE! since DRF 3.10 #list_route() decorator was removed, you should use #action(detail=False) instead, I used #action(detail=False, methods=['PATCH']) to bulk patch, for example Thank you #PolYarBear
So I have an model serializer which consists of
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'name', 'description')
This is my ViewSet
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
This is my URLs.py file:
from django.conf.urls import include, url
from rest_framework import routers
import views
router = DefaultRouter()
router.register('user', views.UserViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^login/', include('rest_framework.urls', namespace='rest_framework'))
]
Using the serializer, I can make it print out the objects inside my database. If I have the object PK/ID, I want to be able to update the field id or name of the object. Is there a way I can do that with a patch/post request using the serializer? I'm new to this so I'd love it if someone can help me out with this.
I'm thinking of just doing a POST request, then have it do this:
user = User.objects.get(id=id)
user.name = "XXXXX"
user.save()
But I want to do this using the serializer, using a PATCH request.
the below code will help to you,
**filename : views.py**
from user.models import User
from users.serializers import UserSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class UserList(APIView):
"""
List all users, or create a new user.
"""
def get(self, request, format=None):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
def post(self, request, format=None):
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)
class UserDetail(APIView):
"""
Retrieve, update or delete a user instance.
"""
def get_object(self, pk):
try:
return User.objects.get(pk=pk)
except User.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
user = self.get_object(pk)
serializer = UserSerializer(user)
return Response(serializer.data)
def put(self, request, pk, format=None):
user = self.get_object(pk)
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, pk, format=None):
user = self.get_object(pk)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
**filename : urls.py**
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from users import views
urlpatterns = [
url(r'^users/$', views.UserList.as_view()),
url(r'^user/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
Reference : http://www.django-rest-framework.org/tutorial/3-class-based-views/
Django rest framework comes with some pre-defined concrete generic views such as UpdateAPIView, RetrieveUpdateAPIView.
First you need to create a view for user which uses one of the views which can update. The update views provides handlers for patch method on the view.
RetrieveUpdateAPIView
Used for read or update endpoints to represent a single model instance.
Provides get, put and patch method handlers.
Now, use this to create a view:
class UserDetail(generics.RetrieveUpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
To access this view you need to have a url which uses user's primary key to access the user:
url(r'users/(?P<pk>\d+)/$', UserDetail.as_view(), name='api-user-detail'),
Then using PATCH call you can update the user's name.
Since you're using a ModelViewset, this capability should be built in. If you use the browsable API to navigate to /user/<pk>/, you'll see the operations you can perform on that object. By default, a ModelViewset provides list(), retrieve(), create(), update(), and destroy() capability.
http://www.django-rest-framework.org/api-guide/viewsets/#modelviewset
You can also override any or all of the provided methods, however an update of a single object is built in to DRF ModelViewsets. Use curl to try a PATCH to /user/<pk>/ with the information you'd like to update.