I have a very strange error when using Django Rest Framework. When ever I use the RetrieveAPIView and the data is found I get a error, when data is not found I get the normal window showing the JSON of
{
"detail": "Not found."
}
urls.py
from django.conf.urls import url, include
from django.contrib import admin
from items.views import ItemRetrieveView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/(?P<pk>\d+)/$', ItemRetrieveView.as_view()),
]
seriliazers.py
from rest_framework import serializers
from .models import Item
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('pk','name','desc','created')
view.py- When I change RetrieveAPIViews to RetrieveUpdateDestroyAPIView I always get 'str' object is not callable even when data does not exist.
from django.shortcuts import render
from rest_framework import generics
from .models import Item
from .serializers import ItemSerializer
class ItemRetrieveView(generics.RetrieveAPIView):
lookup_field = 'pk'
queryset = Item.objects.all()
serializer_class = 'ItemSerializer'
model.py
from django.db import models
class Item(models.Model):
name = models.CharField(max_length = 30)
created = models.DateField(auto_now_add = True)
desc = models.CharField(max_length = 30)
def __str__(self):
return '%s' % (self.name)
serializer_class = 'ItemSerializer'
replace 'ItemSerializer' with ItemSerializer, class is expected other than string
serializer_class - The serializer class that should be used for validating and deserializing input, and for serializing output. Typically, you must either set this attribute, or override the get_serializer_class() method.
get_serializer_class(self)
Returns the class that should be used for the serializer. Defaults to returning the serializer_class attribute.
You can either returns class ItemSerializer or override get_serializer_class(self) like:
def get_serializer_class(self):
return ItemSerializer
You are assigning string value to serializer_class. In your code change
serializer_class = 'ItemSerializer'
to
serializer_class = ItemSerializer
Related
I have created an API from Database, I can view the API but I am unable to do a query via URL for example: 127.0.0.1:8000/author?author_id=9, I am not sure where to add the query code. I want to filter using fields. Here is my models.py
class AuthorAPI(models.Model):
author_id=models.IntegerField()
name=models.TextField()
author_img_url=models.TextField()
title=models.TextField()
first_published_at=models.DateTimeField()
excerpt=models.TextField()
class Meta:
db_table = 'view_author'
serializers.py
from rest_framework import serializers
from .models import SortAPI, AuthorAPI
class AuthorAPISerializer(serializers.ModelSerializer):
class Meta:
model=AuthorAPI
fields='__all__'
views.py
from .serializers import APISerializer,AuthorAPISerializer
from .models import SortAPI, AuthorAPI
from rest_framework.response import Response
from rest_framework.decorators import api_view
#api_view(['GET'])
def getauthor(request):
if request.method == 'GET':
results = AuthorAPI.objects.all()
serialize = AuthorAPISerializer(results, many=True)
return Response(serialize.data)
In your views, use a ModelViewset
And add the fliter_backend attribute:
filter_backends = [django_filters.rest_framework.DjangoFilterBackend]
See here in the docs:
https://www.django-rest-framework.org/api-guide/filtering/#setting-filter-backends
class AuthorViewset(viewsets.ReadOnlyModelViewset):
serializer_class = AuthorAPISerializer
queryset = AuthorAPI.objects.all()
filter_backends = [django_filters.rest_framework.DjangoFilterBackend]
IMPORTANT
Using django_filter will require you to install additional requirements, buts its well worth it, see installation steps for django_filter here:
https://django-filter.readthedocs.io/en/stable/guide/install.html
And in your urls.py you need to register your viewser with a SimpleRouter as described in the docs here:
https://www.django-rest-framework.org/api-guide/viewsets/#example
Additionally, you'll need to set the filterset_fields to tell DRF what fields you want to allow the user to filter with.
As specified in the docs here:
https://django-filter.readthedocs.io/en/stable/guide/rest_framework.html#using-the-filterset-fields-shortcut
And important word of warning which might not be emphasised enough in the documentation is this point:
Note that using filterset_fields and filterset_class together is not supported.
Once complete, if you browse to /author you should see some filter controls available, et voila
You can use request.GET to get data from URL parameters.
Give this a try
#api_view(['GET'])
def getauthor(request):
if request.method == 'GET':
results = AuthorAPI.objects.all()
# get author_id from the url query parameter
author_id = request.GET.get('author_id', None)
#if author_id is present in the url query parameter then filter the resluts queryset based on the author_id
if author_id:
results = results.filter(author_id=author_id)
serialize = AuthorAPISerializer(results, many=True)
return Response(serialize.data)
Thanks to Swift but there was some errors, viewsets.ReadOnlyModelViewset wasn't working perfectly so I tried this
views.py
import django_filters.rest_framework
from django.contrib.auth.models import User
from rest_framework import generics,viewsets,filters
from django_filters.rest_framework import DjangoFilterBackend,OrderingFilter
from rest_framework.pagination import PageNumberPagination
from rest_framework.renderers import JSONRenderer
class CustomPagination(PageNumberPagination):
page_size = 50
page_size_query_param = 'page_size'
max_page_size = 1000
class AuthorViewset(generics.ListAPIView):
renderer_classes = [JSONRenderer]
pagination_class = CustomPagination
serializer_class = AuthorAPISerializer
queryset = AuthorAPI.objects.all()
filter_backends = [DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter]
filterset_fields = ['name', 'id','author_id','status','title','first_published_at','story_type']
search_fields=['id','author_id','name','title','first_published_at']
ordering_fields=['id','author_id','name','title','first_published_at']
class Meta:
name="AuthorViewset"
I could have used Sumithran's answer but it was a bit complex if I would like to allow multiple fields because for every field I had to add the same code with some modification which could increase code lines.
I recently started learning Django. I want to display one news item, but when I open on the link I get an error message:
Cannot resolve keyword 'slug' into field. Choices are: NewsTitles, NewsContent, NewsSlug
Request Method: GET
Request URL: http://127.0.0.1:8000/news/nam-gravida-purus-non/
Django Version: 4.0
Exception Type: FieldError
views.py
from django.views.generic import DetailView
from .models import News
class GetNews(DetailView):
model = News
slug_url_kwarg = 'NewsSlug'
template_name = 'news/single_news.html'
context_object_name = 'single_news'
allow_empty = False
urls.py
from django.urls import path
from .views import GetNews
urlpatterns = [
path('news/<str:NewsSlug>/', GetNews.as_view(), name='news'),
]
models.py
from django.db import models
from django.urls import reverse_lazy
class News(models.Model):
NewsTitles = models.CharField(max_length=120)
NewsContent = models.TextField(max_length=255)
NewsSlug = models.SlugField(max_length=255)
def __str__(self):
return self.NewsTitles
def get_absolute_url(self):
return reverse_lazy('news', kwargs={'NewsSlug': self.NewsSlug})
What am I doing wrong?
First of all do not call your slug "NewSlug" with uppercase but all lower case "newslug" or even better "new_slug", the name itself should be more descriptive as well.
Finally you need to tell your view which field to use, you can define that with the following attribute :
slug_field = "NewSlug"
Note : Attribute of a class should not be camel case but snake case
Hello dear stack overflowers,
I've set up a Django project with restful framework and I use JSON response in order to retrieve data from the server in a structured manner.
models.py
class Container(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=False, default='content')
content = models.TextField()
class Meta:
ordering = ['created']
The problematic code:
views.py
class ContentView(RetrieveAPIView):
queryset = Container.objects.all()
serializer_class = ContainerSerializer
def get_object(self):
queryset = self.get_queryset()
serializer = ContainerSerializer(queryset,many=True)
return JsonResponse(serializer.data , safe=False)
Gives the following error when being executed:
AttributeError: Got AttributeError when attempting to get a value for field `title` on serializer `ContainerSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `JsonResponse` instance.
Original exception text was: 'JsonResponse' object has no attribute 'title'.
[21/May/2021 17:27:13] "GET /content/ HTTP/1.1" 500 18789
To be as clear as possible I'll attach the serializer's code:
serializers.py
class ContainerSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=True, allow_blank=False, max_length=100)
content = serializers.CharField()
def create(self, validated_data):
return Container.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.title = validated_data.get('title', instance.title)
instance.content = validated_data.get('content', instance.content)
instance.save()
return instance
Before switching to RetrieveAPIView, everything worked well with the test server.
The error arised while switching to this new-for-me method of making requests.
Any help will be appreciated!
Let's try model serializers like so: Remeber, you need to update the serializers.py, views.py, and urls.py file to get this to work:
serialiers.py
from rest_framework import serializers
from . import models
class ContainerSerializer(serializers.ModelSerializer):
class Meta:
model = models.Container
fields = ['id', 'created', 'title', 'content']
views.py
from rest_framework import viewsets
from . import serializers
from . import models
class ContainerViewSet(viewsets.ModelViewSet):
serializer_class = serializers.ContainerSerializer
queryset = models.Container.objects.order_by('id')
urls.py
from django.urls import include, path
from rest_framework import routers
from . import views
# rest:
router = routers.DefaultRouter()
router.register('containers', views.ContainerViewSet)
urlpatterns = [
...
path('api/', include(router.urls))
]
Now we have full access to rest, so we can do get, put, post, patch, and delete requests, etc. A getrequest to the url <base-url>/api/containers should return something like:
[
{
'id' : 1,
'created' : 'YYYY-MM-DD',
'title' : 'title-1',
'content' : 'content-1'
},
{
'id' : 2,
'created' : 'YYYY-MM-DD',
'title' : 'title-2',
'content' : 'content-2'
}
]
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
I am working on a project that returns some metrics from a text.
The user is to enter the text in a textbox and the results are displayed to the user.
My serializers.py
from rest_framework.serializers import ModelSerializer
from .models import Entryt
class CreateEntrySerializer(ModelSerializer):
class Meta:
model = Entryt
fields = ('text',)
class EntryDetailSerializer(ModelSerializer):
class Meta:
model = Entryt
fields = ('sentence_count', 'flesch_ease', 'flesch_grade', 'smog', 'linsear', 'text_standard')
lookup_field = 'pk'
views.py
from rest_framework.generics import CreateAPIView, RetrieveAPIView
from .serializers import EntryDetailSerializer, CreateEntrySerializer, Entryt
class CreateEntryView(CreateAPIView):
model = Entryt
serializer_class = CreateEntrySerializer
queryset = Entryt.objects.all()
class ResultView(RetrieveAPIView):
serializer_class = EntryDetailSerializer
queryset = Entryt.objects.all()
urls.py
from django.conf.urls import url
from .views import ResultView, CreateEntryView
urlpatterns = [
url(r'^', CreateEntryView.as_view(), name='create'),
url(r'^result/(?P<pk>[0-9]+)/$', ResultView.as_view(), name='result'),
]
http://localhost:8000/flesch/result/2/ url like this show's nothing though there is an item with that id in the db.
How do I go about fixing this and any tips on making the code better would be great.