Show objects on APIView - python

I have a model, and I just want to show the data of the model in my /api/
from django.db import models
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
class Book(models.Model):
order_id = models.IntegerField()
isbn = models.IntegerField()
publisher = models.CharField(max_length=256)
school = models.CharField(max_length=256)
price = models.IntegerField()
duration = models.CharField(max_length=10)
order_datetime = models.DateTimeField(auto_now=False, auto_now_add=False)
def __str__(self):
return str(self.order_id)
This is my urls.py:
from django.contrib import admin
from django.urls import path
from filter import views
urlpatterns = [
path('', views.index, name='index'),
path('api/', views.BookApiView.as_view(), name='book_api'),
path('admin/', admin.site.urls),
]
This is my views.py:
from django.shortcuts import render
from rest_framework.views import APIView
from .models import Book
from django.http import JsonResponse
class BookApiView(APIView):
def get(self, request, format=None):
books = Book.objects.all()
return JsonResponse({'model': list(books)})
I get the following error: 'Object of type 'Book' is not JSON serializable'
Regards,
Anthony

Django models can't be JSON serialized implicitly.
You need a serializer to convert the model into a representation that is JSON serializable (primitive dicts, lists, numbers, strings, etc)
Django rest framework serializer docs: http://www.django-rest-framework.org/api-guide/serializers/
class BookSerializer(serializers.Serializer):
order_id = serializers.IntegerField()
isbn = serializers.CharField()
...
class BookApiView(APIView):
def get(self, request, format=None):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return JsonResponse({'model': serializer.data})

Man... You need a 'Serializer' before send the data to the view!
The Serializez class get the abstract data from the django ORM and parse the data easily to JSON.
Create a file serializers.py at the same level of view.py
and:
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
After you create the SerializerBook class, import this on your view and pass the book queryset as the first parameter of the BookSerializer.
...
class BookApiView(APIView):
def get(self, request, format=None):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response(serializer.data)

You should define serializer to convert the model instance data to respective JSON data, So define a serializer.py as below
class BookSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = Book
then in your view, change as below,<br>
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
class BookApiView(APIView):
def get(self, request, format=None):
booksqueryset = Book.objects.all()
serializer = BookSerializer(booksqueryset, many=True)
return Response(data=serializer.data)
Read this DRF ModelSerializer Official Doc for more details

Related

NOT NULL constraint failed: DJANGO Rest Framework

I'm following an udemy tutorial, and all it's going nice until I try to do a POST to create an article on the database.
When I send a POST to /api/posts
with Multipart form:
title: What is Java?
description: Java
order: 1
I receive the error:
NOT NULL constraint failed: posts_post.order
I can't find the solution to this specific situation. So I let you the code of my:
models.py:
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
order = models.IntegerField()
created_at = models.DateTimeField(auto_now_add=True)
serializers.py:
from rest_framework.serializers import ModelSerializer
from posts.models import Post
class PostSerializer(ModelSerializer):
class Meta:
model = Post
fields = ['title', 'description', 'created_at']
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from posts.models import Post
from posts.api.serializers import PostSerializer
class PostApiView(APIView):
def get(self, request):
serializer = PostSerializer(Post.objects.all(), many=True)
return Response(status=status.HTTP_200_OK, data=serializer.data)
def post(self, request):
print(request.POST)
serializer = PostSerializer(data=request.POST)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=status.HTTP_200_OK, data=serializer.data)
I can do a GET request to my api/posts properly. The real problem is the POST request where I should create a new article/post
The order field is not included in the serializer. You need to add order in the fields.
class PostSerializer(ModelSerializer):
class Meta:
model = Post
fields = ['title', 'description', 'order, 'created_at']
You are using input as title, description and order but in your serializer you didn't mention order field so you need to mention order filed in your serializer
class PostSerializer(ModelSerializer):
class Meta:
model = Post
fields = ['title', 'description', 'order, 'created_at']

Only allow a field to be edited and NOT written to in Django Rest Framework

so I am trying to create a todo app using the Django rest Framework, and have my models.py as...
class Task(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
task = models.CharField(max_length=150)
date_created = models.DateTimeField(auto_now=True)
completed = models.BooleanField(default=False)
What I want is that when a user inputs their task, I want the completed attribute to be hidden to the user and automatically set that to false. But then allow the user to change to true or false later on.
With my current serializer.py..
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ('id', 'task', 'date_created', 'completed')
extra_kwargs = {
"date_created":{"read_only":True},
# 'completed':{"read_only":True}
}
And my views.py...
class ListView(viewsets.ModelViewSet):
serializer_class = serializers.TaskSerializer
permission_classes = (IsAuthenticated, permissions.ViewOwnTask)
def get_queryset(self):
return Task.objects.filter(user=self.request.user)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
In my serializer.py, the commented code 'completed':{"read_only":True} allows the user to edit the field and write on that field when uploading, as shown in this image
However when I uncomment the 'completed':{"read_only":True} field, the option of writing the completed field disappears however I am not allowed to edit that field.
Is there anything such as {"edit_only":True}, allowing the user to edit the field only. If you get my point.
Any help would be greatly appreciated.
Thanks!
EDIT
My urls.py is...
router = DefaultRouter()
router.register('task', views.ListView, basename='task')
urlpatterns = [
path('', include(router.urls)),
]
2nd EDIT
Hey #PrakashS now I get this kind of output which I don't want, I want only the completed field to be edited.
Use different serializers for adding and editing task:
from rest_framework import serializers
from tasks.models import Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'
extra_kwargs = {
'completed':{"read_only":True}
}
class TaskEditSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'
And in views you can select serializer based on the add or edit view:
from rest_framework.generics import RetrieveUpdateDestroyAPIView, ListCreateAPIView
from rest_framework.permissions import IsAuthenticated
from .models import Task
from .permissions import IsOwnerOrReadOnly
from .serializers import TaskSerializer, TaskEditSerializer
class ListCreateTaskAPIView(ListCreateAPIView):
serializer_class = TaskSerializer
queryset = Task.objects.all()
permission_classes = [IsAuthenticated]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class RetrieveUpdateDestroyTaskAPIView(RetrieveUpdateDestroyAPIView):
serializer_class = TaskEditSerializer
queryset = Task.objects.all()
permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
urls.py file:
from django.urls import path
from . import views
urlpatterns = [
path('', views.ListCreateTaskAPIView.as_view(), name='get_post_tasks'),
path('<int:pk>/', views.RetrieveUpdateDestroyTaskAPIView.as_view(), name='get_delete_update_task'),
]
permissions.py file:
from rest_framework import permissions
from rest_framework.exceptions import PermissionDenied
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow creator of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the creator of the movie
return obj.user == request.user

How to compare parameter passed through POST method with Django rest framework Model and generate custom response?

I am designing Basic Django rest framework based application, i need to compare external parameters passed through POST method in Postman with Coupon code in database and generate custom response like 'This code is redeemed/validate." or " This is invalid coupon/code."
Here is my Model.py file :
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
class Coupon(models.Model):
code = models.CharField(max_length=50, unique=True)
valid_from = models.DateTimeField()
valid_to = models.DateTimeField()
discount = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(100)])
active = models.BooleanField()
def __str__(self):
return self.code
here is my views.py file:
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Coupon
from .serializers import CouponSerializer
from rest_framework import viewsets
class CouponViewSet(viewsets.ModelViewSet):
queryset = Coupon.objects.all()
serializer_class = CouponSerializer
#api_view(['POST'])
def coupon_redeem(request):
if request.method =='POST':
serializer = CouponSerializer(data=request.data)
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)
here is my Serializer.py file
from rest_framework import serializers
from .models import Coupon
class CouponSerializer(serializers.ModelSerializer):
class Meta:
model = Coupon
fields = '__all__'
Please help if possible, Thank you.
IN Your post method u can filter the desired object like:
if serializer.is_valid():
coup=Coupon.objects.filter(code=serializer.data['code'],active=True).exists()
if(coup=="NULL"):
return Response("This is invalid coupon/code",status=status.HTTP_400_BAD_REQUEST)
else:
return Response("This is valid code",status=status.HTTP_200_OK)

Serializing foreign keys as list in DRF

I want to serialize the data
class Main(models.Model):
title = models.CharField()
class ForeignKey(models.Model):
main = models.ForeignKey(Main,on_related='foreign_key')
I want to get the result like
{'title':'hello', 'foreign_key':'['foreign_key1','foreign_key2','foreign_key3']'
I first thought I could make it work in the 'views.py', but some documents told me that there is a thing like 'listField' in serializer, which has too little examples..
What would be the way here?
Write your serializer as ,
#serializers.py
from rest_framework import serializers
class ForeignKeySerializer(serializers.ModelSerializer):
class Meta:
model = ForeignKey
fields = '__all__'
class MainSerializer(serializers.ModelSerializer):
foreign_key = ForeignKeySerializer(source='foreignkey_set', many=True)
class Meta:
model = Main
fields = ("title", "foreign_key")
then write your views as,
#views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
#api_view()
def sample_view(request):
queryset = Main.objects.all()
serializer = MainSerializer(queryset, many=True)
return Response(data=serializer.data)
References
DRF-Serializer
DRF-views

Unable to Post data using Django REST Framework

I am gettting this error although I am giving proper string in Text and Title fields.I don't know what are the reasons,However i am able to post the values of remaining three fields(author,Created_date,publish_date).
Serializer.py
from rest_framework import serializers
from blog.models import Post
from django.utils import timezone
from rest_framework.validators import UniqueValidator
class blogSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('author','title', 'text','created_date','published_date')
model.py
from django.db import models
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey('auth.User',null=True)
title = models.CharField(max_length=200)
text = models.CharField(max_length=200)
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True,null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
views.py
from blog.models import Post
from .serializers import UserSerializer, GroupSerializer,blogSerializer
from rest_framework import viewsets,status
from rest_framework.decorators import api_view
class blogViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = blogSerializer
here i am posting the data.
#api_view(['GET', 'POST'])
def blog_list(request):
if request.method=='GET':
my_blog=Post.objects.all()
serializers=blogSerializer(my_blog,Many=True)
return JsoResponse(serializers.data,safe=False)
elif request.method=='POST':
data=JSONParser().parse(request)
serializers=blogSerializer(data=data)
if serializers.is_valid():
serializer.save()
return JsonResponse(serializers.data,status=201)
return JsonResponse(serializers.errors,status=400)
I would set up a unit test to test this functionality. It looks like none of your post data is getting to the serializer otherwise the valid fields would have been repopulated once you submit the form and the for is returned with errors. The title and text fields are also the only fields which are required/do not have a default value.
If you are using some form of decorator(or something similar) on the view which accesses request.data, this might be what is causing the issue. Since rest framework modifies request.POST when populating request.data

Categories

Resources