KeyError at /courses/api/course/2/ 'id' - python

I'm trying the RetrieveUpdateDeleteAPIView and my update method gives me a key error every time I update a course object
THE UPDATE METHOD WORKS
api_views.py
from rest_framework.generics import (
RetrieveUpdateDestroyAPIView
)
from .serializers import CourseSerializer
from .models import Course
from django.core import cache
class CourseRetrieveUpdateDestroy(RetrieveUpdateDestroyAPIView):
queryset = Course.objects.all()
lookup_field = 'id'
serializer_class = CourseSerializer
def delete(self, request, *args, **kwargs):
course_id = request.data.get('id')
response = super().delete(request, *args, **kwargs)
if response.status_code == 204:
cache.delete('course_data_{}'.format(course_id))
return response
def update(self, request, *args, **kwargs):
response = super().update(request, *args, **kwargs)
if response.status_code == 200:
from django.core.cache import cache
course = response.data
cache.set('course_data_{}'.format(course['id']), {
'title' : course['title'],
'description': course['description'],
'featured': course['featured'],
})
return response
serializers.py
from rest_framework import serializers
from .models import Course
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ('title', 'description', 'issued_at', )
def to_representation(self, instance):
data = super().to_representation(instance)
data['time_passed'] = instance.time_passed()
data['is_fresh'] = instance.is_fresh
return data
urls.py
from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
from .views import (
CourseListView,
CourseDetailView
)
from .api_views import (
#CourseList,
#CourseCreate,
CourseRetrieveUpdateDestroy
)
app_name = 'courses'
urlpatterns = [
path('', CourseListView.as_view(), name="course_list"),
path('course/<int:pk>/', CourseDetailView.as_view(), name="course_detail"),
#api-views
path('api/course/<int:id>/', CourseRetrieveUpdateDestroy.as_view(), name="course_rud_api"),
#path('api/list/', CourseList.as_view(), name="course_list_api"),
#path('api/create/', CourseCreate.as_view(), name="course_create_api"),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
**Whenever I try to update an object of given id and hit enter, a KeyError at /courses/api/course/2/ is returned (id=2 as an example)
'id' being the key.
Why does it give me a key error for fields that I have not requested to serialize in the serializers.py? The model updates even after it redirects me to the error page.
How do i resolve this error or avoid this error page?

You didnt include the id field in your serializer fields, so it will not be in the response data. Try this:
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ('id', 'title', 'description', 'issued_at', )
id will by default be a read-only field. So the user cannot override it when sending data, but it will be in the sent response data.

Related

Django How to bring data into url from DB?

Models.py
from django.db import models
# Create your models here.
class reviewData(models.Model):
building_name = models.CharField(max_length=50)
review_content = models.TextField()
star_num = models.FloatField()
class buildingData(models.Model):
building_name = models.CharField(max_length=50)
building_loc = models.CharField(max_length=50)
building_call = models.CharField(max_length=20)
views.py
# Create your views here.
from django.shortcuts import render
from rest_framework.response import Response
from .models import reviewData
from .models import buildingData
from rest_framework.views import APIView
from .serializers import ReviewSerializer
class BuildingInfoAPI(APIView):
def get(request):
queryset = buildingData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
class ReviewListAPI(APIView):
def get(request):
queryset = reviewData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
urls.py
from django.contrib import admin
from django.urls import path
from crawling_data.views import ReviewListAPI
from crawling_data.views import BuildingInfoAPI
urlpatterns = [
path('admin/', admin.site.urls),
path('api/buildingdata/', BuildingInfoAPI.as_view()),
#path('api/buildingdata/(I want to put building name here)', ReviewListAPI.as_view())
]
I am making review api.
I want to use building name as url path to bring reviews for specific buildings
For example, there are a, b, c reviews
a, b reviews are for aaabuilding
c reviews are for xxxbuilding
api/buildingdata/aaabuilding (only shows aaabuilding review)
{
building_name = aaabuilding
review_content = a
star_num = 5
building_name = aaabuilding
review_content = b
star_num = 3
}
api/buildingdata/xxxbuilding (only shows xxxbuilding review)
{
building_name = xxxbuilding
review_content = c
star_num = 4
}
I've searched some dynamic url posts, but they were not that i want.
Is there any way to bring building name into url from db?
In urls.py
path('api/buildingdata/<str:building>/', BuildingInfoAPI.as_view()),
And in views.py
class BuildingInfoAPI(APIView):
def get(request, building):
queryset = buildingData.objects.filter(building_name__contains=building)
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
Hope this will solve the issue
I suggets you take a look at the django documentation, this is pretty well explained there, here is a useful link
In your urls.py, you should put:
from django.contrib import admin
from django.urls import path
from crawling_data.views import ReviewListAPI
from crawling_data.views import BuildingInfoAPI
urlpatterns = [
path('admin/', admin.site.urls),
path('api/buildingdata/', BuildingInfoAPI.as_view()),
# added <str:building> to url
path('api/buildingdata/<str:building>', ReviewListAPI.as_view())
]
And in your views.py:
# Create your views here.
from django.shortcuts import render
from rest_framework.response import Response
from .models import reviewData
from .models import buildingData
from rest_framework.views import APIView
from .serializers import ReviewSerializer
class BuildingInfoAPI(APIView):
def get(request):
queryset = buildingData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
class ReviewListAPI(APIView):
# added another argument, retrieved from url
def get(request, building):
# changed .all() to .filter()
queryset = reviewData.objects.filter(building_name = building)
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)

Django REST framework error - name is not defined

I have a Django 2.2 that has two apps - status and updates:
django_api
|
status
|
api
|
updates
In django_api/urls.py:
from django.contrib import admin
from django.urls import include, path
from updates.views import (
json_example_view,
JsonCBV,
JsonCBV2,
SerializedListView,
SerializedDetailView
)
from status.api.views import
StatusListSearchAPIView
urlpatterns = [
path('admin/', admin.site.urls),
path('api/status/', status.api.urls),
path('api/updates/', updates.api.urls),
In django_api/status/api/views.py:
from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import StatusSerializer
from status.models import Status
class StatusListSearchAPIView(APIView):
permission_classes = []
authentication_classes = []
def get(self, request, format = None):
qs = Status.objects.all()
serializer = StatusSeralizer(qs, many = True)
return Response(serializer.data)
def post(self, request, format=None):
qs = Status.objects.all()
serializer = StatusSeralizer(qs, many = True)
return Response(serializer.data)
class StatusAPIView(generics.ListAPIView):
permission_classes = []
authentication_classes = []
queryset = Status.objects.all()
serializer_class = StatusSeralizer
def get_queryset(self):
qs = Status.objects.all()
query = self.request.GET.get('q')
if query is not None:
qs = qs.filter(content_icontains = query)
return qs
In django_api/status/api/serializers.py:
from rest_framework import serializers
from django import forms
from status.models import Status
class StatusSerializer(serializers.ModelSerializer):
class Meta:
model = Status
fields = [
'user',
'content',
'image']
def validate_content(self, value):
if len(value) > 10000:
raise serializers.ValidationError("This is way too long.")
return value
def validate(self, data):
content = data.get("content", None)
if content == "":
content = None
image = data.get("image", None)
if content is None and image is None:
raise serializers.ValidationError("content or image is required.")
return data
When I run python manage.py runserver, I am getting an error:
File "...\status\api\views.py", line 26, in StatusAPIView
serializer_class = StatusSeralizer
NameError: name 'StatusSeralizer' is not defined
Updated: as indicated, this was a spelling error. However, after I imported status and from status.api imported urls, I am getting this error:
...\urls.py", line 39, in <module>
path('api/status/', status.api.urls),
...File "C:\Users\fbagi\AppData\Roaming\Python\Python37\site-
packages\django\urls\conf.py", line 73, in _path
raise TypeError('view must be a callable or a list/tuple in the case of
include().')
TypeError: view must be a callable or a list/tuple in the case of
include().
This is my status/api/urls.py:
from django.contrib import admin
from django.urls import path
from .views import StatusAPIView, StatusCreateAPIView
urlpatterns = [
path('/', StatusAPIView.as_view()),
path('create/', StatusCreateAPIView.as_view()),
]
Why am I getting this error?
It's a typo:
You are calling: StatusSeralizer but it is: StatusSerializer
I dont see StatusCreateAPIView in you views file. Have you created this view?
Try just commenting or removing path('create/', StatusCreateAPIView.as_view()), and see If you still get an error.
Try it bro:
from rest_framework import status.
Tell me if you have sucess!

django-rest-framework: model serializer when using ENUMS and source='get_label_display'

Lately I have been working on my first API based on django framework and I got an issue. Here is my code:
models.py
from django.db import models
from multiselectfield import MultiSelectField
COUNTRY_LIST = [('PL', 'Poland'), ('DE', 'Germany'), ('FI', 'Finland'), ('DK', 'Denmark'), ('SE', 'Sweden')]
CLIENTS_LIST = [('CP1', 'Company1'), ('CP2', 'Company2'), ('CP3', 'Company3')]
TRANSPORTS_LIST = [('V', 'Vehicle'), ('P', 'Plane'), ('T', 'Train'), ('S', 'Ship')]
STATUS_LIST = [('NW', 'New'), ('WC', 'Wait for confirmation'), ('AC', 'Accepted'), ('CL', 'Closed')]
class Trip(models.Model):
startDate = models.DateField()
endDate = models.DateField()
place = models.CharField(max_length=100)
country = models.CharField(choices=COUNTRY_LIST, max_length=2)
client = models.CharField(choices=CLIENTS_LIST, max_length=3, default='NA')
transport = MultiSelectField(choices=TRANSPORTS_LIST)
acommodations = models.BooleanField()
tripStatus = models.CharField(
choices=STATUS_LIST, max_length=2, default='NW')
remarks = models.TextField(blank=True)
employeeId = models.IntegerField()
tripIdentifier = models.CharField(max_length=10)
serializers.py
from rest_framework import serializers
from trips.models import Trip, COUNTRY_LIST, CLIENTS_LIST, TRANSPORTS_LIST, STATUS_LIST
# Trip Serializer
class TripSerializer(serializers.ModelSerializer):
country = serializers.CharField(source='get_country_display')
client = serializers.CharField(source='get_client_display')
transport = serializers.CharField(source='get_transport_display')
tripStatus = serializers.CharField(source='get_tripStatus_display')
class Meta:
model = Trip
fields = '__all__'
api_views.py
from rest_framework.exceptions import ValidationError
from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveUpdateDestroyAPIView
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
from trips.serializers import TripSerializer
from trips.models import Trip
import re
class TripList(ListAPIView):
queryset = Trip.objects.all()
serializer_class = TripSerializer
filter_backends = (DjangoFilterBackend, SearchFilter)
search_fields = ("tripIdentifier", "id")
filter_fields = ('id', 'tripStatus', 'employeeId')
class TripCreate(CreateAPIView):
serializer_class = TripSerializer
def create(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)
class TripRetrieveUpdateDelete(RetrieveUpdateDestroyAPIView):
queryset = Trip.objects.all()
lookup_field = 'id'
serializer_class = TripSerializer
def delete(self, request, *args, **kwargs):
trip_id = request.data.get('id')
response = super().delete(request, *args, **kwargs)
if response.status_code == 204:
from django.core.cache import cache
cache.delete('trip_data_{}'.format(trip_id))
return response
def update(self, request, *args, **kwargs):
response = super().update(request, *args, **kwargs)
if response.status_code == 200:
from django.core.cache import cache
trip = response.data
cache.set('trip_data_{}'.format(trip['id']), {
'startDate': trip['startDate'],
'endDate': trip['endDate'],
'place': trip['place'],
'employeeId': trip['employeeId'],
})
return response
urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.conf.urls import url
from django.contrib import admin
from django.urls import path, include
import employee.views
import employee.api_views
import trips.views
import trips.api_views
urlpatterns = [
path('admin/', admin.site.urls),
path('employee', employee.api_views.EmployeeList.as_view()),
path('employee/new', employee.api_views.EmployeeCreate.as_view()),
path('employee/<int:id>',
employee.api_views.EmployeeRetrieveUpdateDelete.as_view()),
path('trip', trips.api_views.TripList.as_view()),
path('trip/new', trips.api_views.TripCreate.as_view()),
path('trip/<int:id>', trips.api_views.TripRetrieveUpdateDelete.as_view())
]
Here is an issue description:
Get, Put and Delete requests works fine. But when I invoke POST request and try to add new Trip I got an error:
TypeError at /trip/new
Got a `TypeError` when calling `Trip.objects.create()`. This may be because you have a writable field on the serializer class that is not a valid argument to `Trip.objects.create()`. You may need to make the field read-only, or override the TripSerializer.create() method to handle this correctly.
Original exception was:
Traceback (most recent call last):
File "C:\Users\User\.virtualenvs\RadiolineExtranet-iRF8Rd_0\lib\site-packages\rest_framework\serializers.py", line 932, in create
instance = ModelClass._default_manager.create(**validated_data)
File "C:\Users\User\.virtualenvs\RadiolineExtranet-iRF8Rd_0\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\User\.virtualenvs\RadiolineExtranet-iRF8Rd_0\lib\site-packages\django\db\models\query.py", line 420, in create
obj = self.model(**kwargs)
File "C:\Users\User\.virtualenvs\RadiolineExtranet-iRF8Rd_0\lib\site-packages\django\db\models\base.py", line 501, in __init__
raise TypeError("%s() got an unexpected keyword argument '%s'" % (cls.__name__, kwarg))
TypeError: Trip() got an unexpected keyword argument 'get_country_display'
Can you help me a little bit to understand what is wrong with my code ?
The stack trace shows it trying to create: self.model(**kwargs). You told it that certain fields are backed by the model, but in a different column name, and so it tries to save them:
serializers.CharField(source='get_country_display')
You can try:
Use CharField('get_country_display', read_only=True)
ADD read_only_fields=['get_country_display', ...] to the Meta class
Use a SerializerMethodField which is readonly, and call the function manually

Non_field_errors no data provided in django webapi

I am new in Django and python. Now I am trying to do web API with Django and python. I can get the get request but when I request the post method, this error is shown
"non_field_errors": [
"No data provided"
]
View.py=>
from rest_framework.generics import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Allowance
from .serializers import AllowanceSerializer
# Create your views here.
class AllowanceAPIView(APIView):
def get(self,request,pk=None):
if pk:
allowance=get_object_or_404(Allowance.objects.all(),pk=pk)
serializer = AllowanceSerializer(allowance)
return Response({serializer.data})
allowance=Allowance.objects.all()
serializer = AllowanceSerializer(allowance,many=True)
return Response({"allowance":serializer.data})
def post(self,request):
allowance = request.data.get('allowance')
serializer = AllowanceSerializer(data=allowance)
if serializer.is_valid(raise_exception=True):
allowance_saved=serializer.save()
return Response({"success":"Allowance '{}' created successfully".format(allowance_saved.AllowID)})
def put(self,request,pk):
save_allowance = get_object_or_404(Allowance.objects.all(),pk=pk)
data = request.data.get('allowance')
serializer = AllowanceSerializer(instance=save_allowance,data=data,partial=True)
if serializer.is_valid(raise_exception = True):
allowance_saved=serializer.save()
return Response({"sucess": "Allowance '{}' updated successfully".format(allowance_saved.AllowID)})
def delete(self,request,pk):
#Get object with this pk
allowance = get_object_or_404(Allowance.objects.all(),pk=pk)
allowance.delete()
return Response({"message":"Allowance with id '{}' has been deleted.".format(pk)},status=204)
urls.py inside app =>
from django.conf.urls import url
from .views import AllowanceAPIView
urlpatterns = [
url(r'^$', AllowanceAPIView.as_view(), name='post-listcreate'),
url(r'^(?P<pk>\d+)/$', AllowanceAPIView.as_view(), name='post-listcreate')
]
urls.py inside project =>
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
url(r'^admin/', admin.site.urls),
# url(r'^api/auth/login/$', obtain_jwt_token, name='api-login'),
url(r'^api/allowances_mas/', include('tmswebapi.urls')),
]
sample API request=>
{
"AllowID": "Allow1",
"AllowDesc": "Allow1 Description",
"AllowAmt": "11.00",
"AllowType": "MEAL",
"Created_DT": "2019-06-18T18:09:00Z",
"Created_Usr": "Admin",
"LastModified_Usr": "",
"LastModified_DT": "2019-06-18T18:09:00Z"
}
Serializer =>
from rest_framework import serializers
import datetime
from .models import Allowance
class AllowanceSerializer(serializers.ModelSerializer):
class Meta:
model=Allowance
fields = "__all__"
def create(self,validated_data):
return Allowance.objects.create(**validated_data)
def update(self,instance,calidated_data):
instance.AllowDesc = validated_data.get('AllowDesc',instance.AllowDesc)
instance.AllowAmt = validated_data.get('AllowAmt',instance.AllowAmt)
instance.AllowType = validated_data.get('AllowType',instance.AllowType)
instance.LastModified_Usr = "Admin"
instance.LastModified_DT = datetime.datetime.now()
instance.save()
return instance
Is it because of urls or because of data format?
It's returning error from on of if serializer.is_valid(raise_exception = True): lines.
It means data is None somewhere.
Debug your code to make sure data variable has data
def post(self,request):
allowance = request.data
serializer = AllowanceSerializer(data=allowance)
if serializer.is_valid(raise_exception=True):
allowance_saved=serializer.save()
return Response({"success":"Allowance '{}' created successfully".format(allowance_saved.AllowID)})
Now try this

Django rest framework serialization error

I have a django model that looks like this:
class AcademicProgramsManager(models.Manager):
def get_by_natural_key(self, acad_program_id, program_title, required_credits):
return self.get(acad_program_id = acad_program_id, program_title = program_title, required_credits = required_credits)
class AcademicPrograms(models.Model):
objects = AcademicProgramsManager()
acad_program_id = models.IntegerField(primary_key=True)
acad_program_category = models.ForeignKey(AcademicProgramCategories)
acad_program_type = models.ForeignKey(AcademicProgramTypes)
acad_program_code = models.CharField(max_length=25)
program_title = models.CharField(max_length=64)
required_credits = models.IntegerField()
min_gpa = models.FloatField()
description = models.CharField(max_length=1000)
def natural_key(self):
return (self.acad_program_id, self.program_title, self.required_credits)
class StudentAcademicPrograms(models.Model):
student = models.ForeignKey(Students)
academic_program = models.ForeignKey(AcademicPrograms)
credits_completed = models.IntegerField()
academic_program_gpa = models.FloatField()
primary_program = models.BooleanField()
This is my serializers.py file:
from studentapp.models import AcademicPrograms, AcademicProgramsManager, StudentAcademicPrograms
from rest_framework import serializers
class StudentAcademicProgramsSerializer(serializers.ModelSerializer):
class Meta:
model = StudentAcademicPrograms
fields = ('credits_completed','academic_program_gpa','primary_program')
class AcademicProgramsSerializer(serializers.ModelSerializer):
studentacademicprograms = StudentAcademicProgramsSerializer(many = True)
class Meta:
model = AcademicPrograms
fields = ('acad_program_id','program_title','required_credits','studentacademicprograms')
My api.py file looks like this:
from studentapp.models import AcademicPrograms, AcademicProgramsManager, StudentAcademicPrograms
from studentapp.serializers import StudentAcademicProgramsSerializer, AcademicProgramsSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
class AcademicProgramsList(APIView):
def get(self, request, format=None):
academicprograms = AcademicPrograms.objects.all()
serialized_academicprograms = AcademicProgramsSerializer(academicprograms, many=True)
return Response(serialized_academicprograms.data)
class AcademicProgramsDetail(APIView):
def get_onjects(self, pk):
try:
return AcademicPrograms.object.get(pk=pk)
except AcademicPrograms.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
academicprogram = self.get_object(pk)
serialized_academicprogram = AcademicProgramsSerializer(academicprogram)
return Response(serialized_academicprogram.data)
and finally my urls:
from django.conf.urls import patterns, include, url
from rest_framework.urlpatterns import format_suffix_patterns
from studentapp import api
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'texascompletes.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
#API:
url(r'^api/studentacademicprograms/$', api.AcademicProgramsList.as_view()),
url(r'^api/studentacademicprograms/(?P<pk>[0-9]+)/$', api.AcademicProgramsDetail.as_view()),
url(r'^admin/', include(admin.site.urls)),
)
urlpatterns = format_suffix_patterns(urlpatterns)
I am getting the following error when i give my api/studentacademicprograms
'AcademicPrograms' object has no attribute 'studentacademicprograms'
Where am i going wrong?
Try setting the source to the attribute/method name on the model. For example:
studentacademicprograms = StudentAcademicProgramsSerializer(
many=True,
source='studentacademicprograms_set')
The example given in the Django Rest Framework Serializer relations docs sets a related name on the models which matches the attribute name in the serializer (the default). If the names don't match you need to specify them model's source method/attribute to use.

Categories

Resources