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
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)
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!
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
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
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.