Django RestFramework call the Api by the Field - python-3.x

currently i pass the parameter 'id' in the url and i call the API by id however i would like to call API by the parameter.here is views.py`
class post_list(APIView):
def get(self,request,format=None):
post_resource=PostResource()
dataset=Dataset()
post = Post.objects.all()
serializer = PostSerializer(post, many=True)
a=[]
for row in post:
a.append(row)
return Response(serializer.data)
def post(self,request,format =None):
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)
class post_detail(APIView):
def get_object(self, pk):
try:
return Post.objects.get(pk=pk)
except Post.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
post = self.get_object(pk)
serializer = PostSerializer(post)
return Response(serializer.data)
def put(self, request, pk, format=None):
snippet = self.get_object(pk)
serializer = PostSerializer(snippet, 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):
post = self.get_object(pk)
post.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
this is the result when i pass the id in the url`
when i pass the id in the url it's show only the that particular id result however i need view if i pass the other field instead of the id it's show the result based on that.so my question is what should i have to change in the views.py and Urls.py. this is urls.py file`
from django.conf.urls import url
from api import views
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
url(r'^post/$', views.post_list.as_view()),
url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail.as_view()),
]
urlpatterns=format_suffix_patterns(urlpatterns)
This is my serializer.py file`
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
#fields=('ProductName','Score')
fields ='__all__'
`

You should change your url so that it accepts string:
url(r'^post/(?P<pname>[a-zA-Z0-9]+)/$', views.post_detail.as_view())
and then change your get_object method like this:
def get_object(self, pname):
try:
return Post.objects.get(pname=pname)
except Post.DoesNotExist:
raise Http404
But you will issues if pname is not unique, because it will complain that you have more than one such Post.
Hope it helps!

Related

Django rest-framework , Serializer returning assertion Error

I'm extending my current model to have some common properties from other base classes.
Before extending the model, everything was working fine. But after extending, I'm getting the assertion error while performing put and post Operation. I tried my best to resolve it by my own. But not getting where it is going wrong. Can anyone help me on this?
Please find my model and serializers below.
basemodel.py
from django.db import models
class BaseModel(models.Model):
created_at=models.DateTimeField(auto_now=True)
updated_at=models.DateTimeField(auto_now=True)
class Meta:
abstract = True
softdelete.py
from django.db import models
class SoftDeleteModel(models.Model):
is_deleted = models.BooleanField(default=False)
def delete(self):
self.is_deleted = True
self.save()
def restore(self):
self.is_deleted = False
self.save()
class Meta:
abstract = True
movies.py
from django.db import models
from cinimateApp.models.comman.softdelete import SoftDeleteModel
from cinimateApp.models.comman.basemodel import BaseModel
# Create your models here.
class Movies(SoftDeleteModel,BaseModel):
name=models.CharField(max_length=250)
description=models.CharField(max_length=250)
active=models.BooleanField(default=False)
def __str__(self):
return self.name
movieSerializer.py
#Model Serializer
from rest_framework import serializers
from cinimateApp.models.movies import Movies
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movies
fields = '__all__'
# fields=['id', 'name', 'description', 'active']
# exclude=['name']
# field Level Validation
def validate_name(self,value):
if(len(value)<3):
raise serializers.ValidationError('name is too short')
return value
#Objectlevel validation
def validate(self,data):
if(data['name']==data['description']):
raise serializers.ValidationError('name and description should be different')
return
#custome serializer field
name_length=serializers.SerializerMethodField()
def get_name_length(self,object):
return len(object.name)
views.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from cinimateApp.serializers.movieSerializer import MovieSerializer
from cinimateApp.models.movies import Movies
# Create your views here.
class MovieList(APIView):
def get(self,request):
movies=Movies.objects.all()
serializer=MovieSerializer(movies,many=True)
return Response(serializer.data,status=status.HTTP_200_OK)
def post(self,request):
serialiser=MovieSerializer(data=request.data)
if(serialiser.is_valid()):
serialiser.save()
return Response(serialiser.data,status=status.HTTP_201_CREATED)
else:
return Response(serialiser.errors,status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class MovieDetailsAV(APIView):
def get(self,request,id):
try:
movie=Movies.objects.get(pk=id)
serializer=MovieSerializer(movie)
return Response(serializer.data,status=status.HTTP_200_OK)
except Movies.DoesNotExist:
return Response({'Error':'Movie not found'},status=status.HTTP_404_NOT_FOUND)
def put(self,request,id):
try:
movie=Movies.objects.get(pk=id)
serializer=MovieSerializer(movie,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_500_INTERNAL_SERVER_ERROR)
except Movies.DoesNotExist:
return Response({'Error':'Movie not found'},status=status.HTTP_404_NOT_FOUND)
def delete(self,request,id):
try:
movie=Movies.objects.get(pk=id)
movie.delete()
return Response({'message' : 'Content deleted successfully'},status=status.HTTP_204_NO_CONTENT)
except Movies.DoesNotExist:
return Response({'Error':'Movie not found'},status=status.HTTP_404_NOT_FOUND)
def patch(self,request,id):
try:
movie=Movies.objects.get(pk=id)
serializer=MovieSerializer(movie,data=request.data,partial=True)
if(serializer.is_valid()):
serializer.save()
return Response(serializer.data,status=status.HTTP_200_OK)
return Response(serializer.errors,status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except Movies.DoesNotExist:
return Response({'Error':'Movie not found'},status=status.HTTP_404_NOT_FOUND)
I'm getting following errors for put and post requests.
assert value is not None, '.validate() should return the validated data'
AssertionError: .validate() should return the validated data
validate() function should return data so:
def validate(self,data):
if(data['name']==data['description']):
raise serializers.ValidationError('name and description should be different')
return data

how to get a string parametr in drf modelviewset

i need to use a path with an optional paramentr, to specify a user via a srting a request would look like 'api/users/specific_username' or 'api/users' for all users
urls:
router = DefaultRouter()
router.register(r'users', MyUserViewSet, basename='user-me')
views:
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
def get_queryset(self):
queryset = User.objects.all()
if self.kwargs['username']:
username=self.request.GET.get('username')
queryset = User.objects.filter(username=username)
return queryset
username=self.kwargs['username']
returns KeyError
username=self.request.GET.get('username')
returns None
I've managed to achieve that by doing like so:
so for request that looks like so:
http://example.com/api/viewset?username=denvercoder9
the code will look this:
def get_queryset(self):
"""
Optionally restricts the returned purchases to a given user,
by filtering against a `username` query parameter in the URL.
"""
queryset = Purchase.objects.all()
username = self.request.query_params.get('username', None)
if username is not None:
queryset = queryset.filter(purchaser__username=username)
return queryset
or if you really want you override the retrieve:
(haven't tested this code)
def retrieve(self, request, pk=None):
queryset = User.objects.filter(username=pk)
contact = get_object_or_404(queryset, pk=1)
serializer = ContactSerializer(contact)
return Response(serializer.data)

Image Upload serializer not working but is valid and saving

I've tried everything but I cannot figure out why my images for an Avatar won't save to the media folder in Django.
I am happy the front end is passing form data to the AvatarAPIView and I get the following when I print out the data being passed to the view.
<QueryDict: {'myFile': [<InMemoryUploadedFile: 1965.jpg (image/jpeg)>]}>
[07/Feb/2021 10:48:54] "PUT /api/profile/avatar/ HTTP/1.1" 200 31
view.py
from profiles.api.serializers import (UserDisplaySerializer,
SubscriptionSerializer,
AvatarSerializer)
from profiles.models import CustomUser
from rest_framework import status, viewsets
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import UpdateAPIView, GenericAPIView
from rest_framework import mixins
from rest_framework.parsers import MultiPartParser, FileUploadParser, FormParser
from django.http import HttpResponse
class CurrentUserAPIView(APIView):
def get(self, request):
serializer = UserDisplaySerializer(request.user)
return Response(serializer.data)
def patch(self, request):
serializer = UserDisplaySerializer(request.user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserUpdateAPIView(UpdateAPIView):
queryset = CustomUser.objects.all()
serializer_class = UserDisplaySerializer
class AvatarAPIView(APIView):
parser_classes = (MultiPartParser, FormParser)
def get(self, request):
serializer = AvatarSerializer(request.user)
return Response(serializer.data)
def put(self, request, format=None):
serializer = AvatarSerializer(
request.user, data=request.data)
print(request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.py
from rest_framework import serializers
from profiles.models import CustomUser, Subscription
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
exclude = ('id', 'user', )
class UserDisplaySerializer(serializers.ModelSerializer):
subscription = SubscriptionSerializer(read_only=True, many=False)
class Meta:
model = CustomUser
exclude = ('password',)
class AvatarSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('avatar',)
urls.py
from django.urls import path
from django.conf.urls import include
from profiles.api.views import (CurrentUserAPIView,
UserUpdateAPIView,
AvatarAPIView,
)
from rest_framework import routers
urlpatterns = [
path("user/", CurrentUserAPIView.as_view(), name="current-user"),
path("user/update/<int:pk>", UserUpdateAPIView.as_view()),
path("avatar/", AvatarAPIView.as_view(), name='user-avatar'),
]
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
bio = models.CharField(max_length=240, blank=True)
city = models.CharField(max_length=30, blank=True)
avatar = models.ImageField(null=True, blank=True)
I can upload files from the Django admin no problems. It's just when running through the serializer I have issues. Particularly because the data passes is_valid() and a code 200 is issued.
I'm half a day deep and I've got nothing.
not sure if your user is logged in or not;
as your formdata shows:
<QueryDict: {'myFile': [<InMemoryUploadedFile: 1965.jpg (image/jpeg)>]}> [07/Feb/2021 10:48:54] "PUT /api/profile/avatar/ HTTP/1.1" 200 31
In your form data, the "input name" of image is "myFile" while the name of imagefield in your Model and Serializer is "avatar".

how to add a method to a class template view

happy new year everyone...I am new to django and i am working on a project a resume page i need help with the contact me section, i want to do something i seen in a video https://www.youtube.com/watch?v=w4ilq6Zk-08. The book i used to learn only uses class to view templates. below is my code
from django.views.generic import TemplateView
from django.shortcuts import render
# Create your views here.
class ProfilePageView(TemplateView):
template_name = 'femi_profile.html'
def contact(request):
if request.method == "POST":
name = request.POST['name']
email = request.POST['email']
subject = request.POST['subject']
message = request.POST['message']
return render(request, 'femi_profile.html', {'contact_name': name})
else:
return render(request, 'femi_profile.html', {})
After reading the django documentation https://docs.djangoproject.com/en/3.1/topics/class-based-views/intro/ once more and trying different lines of code i finally got that run and i am not asking why is it runing? i figured out how to go about this.
find the correct code below
from django.views.generic import TemplateView
from django.shortcuts import render
# Create your views here.
class ProfilePageView(TemplateView):
template_name = 'femi_profile.html'
def get(self, request, *args, **kwargs):
return render(request, self.template_name, {})
def post(self, request, *args, **kwargs):
if request.method == "POST":
name = request.POST['name']
email = request.POST['email']
subject = request.POST['subject']
message = request.POST['message']
return render(request, self.template_name, {'contact_name': name})

How does one properly create a customized Swagger Schema in the Django Rest Framework?

I am having trouble creating a customizable swagger schema in the Django Rest Framework. I have read pages of documentation, but have not found a clear cut example on how to generate swagger annotations in python.
I am aware that swagger/schema documentation is readily generated when using ViewSets in Django. However, I am solely using APIViews and want to write a customized schema. I have tried creating a CoreAPI schema but am unaware of how to implement it. I am enclosing some of my sample code and some screenshots as well. The screen shots go from what I have to what I want.
Sample code:
urls.py
from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from Views import SampleView as sv
from rest_framework_swagger.views import get_swagger_view
from rest_framework.documentation import include_docs_urls
from rest_framework.renderers import CoreJSONRenderer
from rest_framework.schemas import get_schema_view
schema_view enter code here= get_swagger_view(
title='Sample API')
urlpatterns = [
url(r'^sample/$', pv.SampleList.as_view()),
url(r'^sample/(?P<id>[a-f\d]{24})/$', sv.SampleDetail.as_view()),
url('^schema/$', schema_view),
]
urlpatterns = format_suffix_patterns(urlpatterns)
views.py
from rest_framework.views import APIView
from Manager.SampleManager import SampleManager as sm
_sampleManager = sm()
class SampleList(APIView):
"""
get:
Return a list of all the existing samples.
post:
Create a new sample.
"""
def get(self, request, format=None):
return _sampleManager.getAll()
def post(self, request, format=None):
return _sampleManager.create( request)
class SampleDetail(APIView):
"""
get:
Get a sample.
put:
Update a sample.
delete:
Delete a sample.
"""
def get(self, request, id, format =None):
return _sampleManager.getById( id)
def put(self, request, id, format =None):
return _sampleManager.update( request, id)
def delete(self, request, id, format =None):
return _sampleManager.deleteById( id)
Serializers.py
from rest_framework_mongoengine.serializers import DocumentSerializer
from .modles import Sample, SampleInner
from Serializers.SampleInnerSerializer import SampleInnerSerializer
class SampleSerializer(DocumentSerializer):
other = SampleInnerSerializer(many=True)
class Meta:
model = Sample
fields = '__all__'
def create(self, validated_data):
samples = validated_data.pop('other')
created_instance = super(SampleSerializer, self).create(validated_data)
for sample_data in samples:
created_instance.other.append(SampleInner(**sample_data))
created_instance.save()
return created_instance
def update(self, instance, validated_data):
samples = validated_data.pop('other')
updated_instance = super(SampleSerializer, self).update(instance, validated_data)
for sample_data in samples:
updated_instance.other.append(SampleInner(**sample_data))
updated_instance.save()
return updated_instance
Schema.py
import coreapi
from rest_framework.decorators import api_view, renderer_classes
from rest_framework import renderers, response
schema = coreapi.Document(
title='Sample API',
content={
'sample': coreapi.Link(
url='/sample/',
action='post',
fields=[
coreapi.Field(
name='from',
required=True,
location='query',
description='City name or airport code.'
),
coreapi.Field(
name='to',
required=True,
location='query',
description='City name or airport code.'
),
coreapi.Field(
name='date',
required=True,
location='query',
description='Flight date in "YYYY-MM-DD" format.'
)
],
description='Create partner'
)
}
)
#api_view()
#renderer_classes([renderers.CoreJSONRenderer])
def schema_view(request):
return response.Response(schema)
There is two solution for you in this senario, One "go with the GenricApiView" Two "Create Custom row Schema"
let's go with
-- >solution one.
urls.py
schema_view = get_swagger_view(title='Test All API')
urlpatterns = [
path('swagger2/', schema_view),
]
view.py
class LoginAPIView(generics.GenericAPIView):
serializer_class = LoginSerializer
permission_classes = [permissions.AllowAny]
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Result
--> Solution two:
urls.py
configuration is same as before
views.py
class BlacklistTokenAdding(APIView):
permission_classes = [permissions.AllowAny]
schema = ManualSchema(fields=[
coreapi.Field(
"first_field",
required=True,
location="body",
schema=coreschema.String()
),
coreapi.Field(
"second_field",
required=True,
location="body",
schema=coreschema.String()
),
])
def post(self, request, format='json'):
try:
refresh_token = request.data["refresh_token"]
token = RefreshToken(refresh_token)
token.blacklist()
return Response(status=status.HTTP_200_OK)
except Exception as e:
return Response(status=status.HTTP_400_BAD_REQUEST)
//Note the first_field & second_field is to demonstration you can add here as much field as you want.
Result

Resources