I know that there is something wrong with my urls. But I'm unable to figure it out.
models.py
class Restaraunt(models.Model):
name=models.CharField(max_length=50,blank=True,null=True)
class Schedule(models.Model):
restaraunt=models.ForeignKey(Restaraunt, on_delete=models.CASCADE,related_name='restaraunt_name')
#days=models.CharField(choices=DAYS,max_length=255)
opening_time=models.TimeField(auto_now=False,auto_now_add=False)
closing_time=models.TimeField(auto_now=False,auto_now_add=False)
def __str__(self):
return str(self.restaraunt)
class Restarasunt(viewsets.ViewSet):
def create(self,request):
try:
name=request.data.get('name')
if not name:
return Response({"message": "name is rerquired!","success":False},
status=status.HTTP_200_OK )
res_obj=Restaraunt()
res_obj.name=name
print(res_obj.name)
res_obj.save()
return Response("Restaurant addedd successfully")
except Exception as error:
traceback.print_exc()
return Response({"message":str(error),"success":False},status = status.HTTP_200_OK)
class ScheduleViewSet(viewsets.ViewSet):
def create(self,request,pk):
try:
res_obj=Restaraunt.objects.filter(pk=pk)
print('hie',res_obj)
data=request.data
opening_time=data.get('opening_time')
closing_time=data.get('closing_time')
sce_obj=Schedule()
sce_obj.opening_time=opening_time
sce_obj.closing_time=closing_time
sce_obj.restaraunt=res_obj
sce_obj.save()
return Response("")
except Exception as error:
traceback.print_exc()
return Response({"message":str(error),"success":False},status = status.HTTP_200_OK)
URLS.PY
from rest_framework.routers import DefaultRouter
from auth1 import views
router=DefaultRouter()
router.register(r'retaraunt', views.Restarasunt, basename='Restarasunt')
router.register(r'Timings', views.ScheduleViewSet, basename='ScheduleViewSet')
urlpatterns = router.urls
As showed in the documentation you need to add retrieve method for your class
class UserViewSet(viewsets.ViewSet):
"""
A simple ViewSet for listing or retrieving users.
"""
def list(self, request):
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = User.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = UserSerializer(user)
return Response(serializer.data)
I don't think that the create view is meant to be used with "pk". Can you try getting the "pk" value from request.data and use it to get the Restaraunt object
Related
I'm trying to create API for liking a post. This works for liking a post
but I get error when adding the return HttpResponse/Response statements gives an error:
AttributeError at /api/posts/like/4/
'HttpResponse' object has no attribute 'model'
Request Method: GET
Request URL: http://127.0.0.1:8000/api/posts/like/4/
Django Version: 2.0.7
views.py
class LikeDetailAPIView(RetrieveAPIView):
serializer_class = PostSerializer
def get_queryset(self):
user = self.request.user
post_id = self.kwargs['pk']
like = Like(post=Post.objects.get(id=post_id), user=user)
user_like = Like.objects.filter(post=post_id, user=user)
if user_like.exists():
user_like.delete()
content = {'message': 'unliked'}
return Response(content, status=status.HTTP_202_ACCEPTED)
else:
like.save()
content = {'message': 'like'}
return Response(content, status=status.HTTP_202_ACCEPTED)
urls.py
url(r'^like/(?P<pk>.+)/$',LikeDetailAPIView.as_view(), name='likeapi'),
What I am intending to do is return a success message.
serializer.py
class LikeListSerializer(serializers.ModelSerializer):
class Meta:
model = Like
fields = [
'user',
'post',
'time',
]
Any links that I can refer to?
From the official DRF doc,
get_queryset(self) method returns the queryset that should be used for list views, and that
should be used as the base for lookups in detail views. Defaults
to returning the queryset specified by the queryset attribute.
From your comments, I understood that, you need to show some response when you access the API (detail-view).
Since you are using RetrieveAPIView class, you have to override retrieve() method, as
from rest_framework.generics import RetrieveAPIView
class LikeDetailAPIView(RetrieveAPIView):
serializer_class = PostSerializer
def get_queryset(self):
return Like.objects.filter(post=self.kwargs['pk'], user=self.request.user)
def retrieve(self, request, *args, **kwargs):
if self.get_queryset().exists():
self.get_queryset().delete()
content = {'message': 'unliked'}
return Response(content, status=status.HTTP_202_ACCEPTED)
like = Like(post=Post.objects.get(id=post_id), user=user)
like.save()
content = {'message': 'like'}
return Response(content, status=status.HTTP_202_ACCEPTED)
Now you can access the endpoint, /api/posts/like/4/ by HTTP GET method
I'm trying to update an object of my database (but only one of the field), the problem is that when I try to make the update i get an error that says that the PUT method is not allowed.
Here's my View:
class DeviceViewSet(viewsets.ModelViewSet):
"""
Show, create and filter devices.
"""
queryset = Device.objects.all()
serializer_class = DeviceSerializer
def list(self, request, *args, **kwargs):
devices = Device.objects.filter(user=request.user.pk, role='E')
serializer = DeviceSerializer(devices, many=True)
return Response(serializer.data)
def create(self, request, *args, **kwargs):
data = {
'registration_id': request.data['regId'], 'user': request.user.pk, 'device_id': request.data['imei'],
'type': 'android', 'label': request.data['label'], 'role': request.data['role']
}
serializer = DeviceSerializer(data=data)
if serializer.is_valid():
serializer.save()
device = Device.objects.filter(device_id=request.data['imei'])
device.send_message("Enhorabuena!", "El dispositivo se ha registrado correctamente.")
return Response(serializer.data)
return Response(serializer.errors)
def update(self, request, *args, **kwargs):
device = Device.objects.filter(device_id=request.data['imei'])
device.registration_id = request.data['regId']
device.save()
serializer = DeviceSerializer(device)
return Response({'ok': 'oks'})
My serializer:
class DeviceSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), required=False)
class Meta:
model = Device
fields = '__all__'
My url:
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from decaught import views
urlpatterns = [
url(r'^devices/$', views.DeviceViewSet),
]
urlpatterns = format_suffix_patterns(urlpatterns)
I'm using Postman to send a PUT Request:
Any idea what is wrong?
When PUTting the resource identifier should be in the URL (pk). PUT request is idempotent.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT
In the DRF documentation, pk is passed as an argument to the update method
def update(self, request, pk=None):
pass
http://www.django-rest-framework.org/api-guide/viewsets/#viewset-actions
Instead of passing it as a key:value pair and accessing it through request.data PUT call should be like
localhost:8000/devices/<PK-HERE>/
(sorry for not so good english)
The error is in our URL. You need to select some device to PUT information. Try with localhost:8000/devices/1/. I'm assuming that your API take objects by pk
This is my question asked 2 days back. I used Louis Barranqueiro's answer to solve my problem.
Now I want to add current page number as well as page_size in the serialized data. I know I have to customize the get_paginated_response method in PageNumberPagination class, but when I do that I get this error:
My code
def get_paginated_response(self, data, request):
# import pdb
# pdb.set_trace()
return Response(OrderedDict([
('next', self.get_next_link()),
('current', self.get_current_link()),
('previous', self.get_previous_link()),
('results', data)
]))
def get_queryset(self, request):
product_sync_ts = self.request.GET.get('product_sync_ts', None)
if product_sync_ts:
product = Product.objects.filter(....)
)
# return self.get_paginated_response(product, self.request)
return Response(product)
else:
content = {'details': "Bad Request"}
raise APIException400(request, content)
def get(self, request, format=None):
products = self.get_queryset(request)
serializer = SyncedProductSerializer(instance={'products': products})
# product = self.paginate_queryset(serializer, request)
return self.get_paginated_response(serializer, request)
# return self.get_paginated_response(serializer.data, request)
Error:
File "/Users/Documents/content-api/venv/lib/python2.7/site-packages/rest_framework/pagination.py", line 242, in get_next_link
if not self.page.has_next()
AttributeError: 'PaginatedProductList' object has no attribute 'page'
Some one might wanna try:
REST_FRAMEWORK = {
'PAGE_SIZE': 20,
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',}
on settings.py
with a view like
class GeneralManagementAPIView(generics.ListAPIView):
queryset = GeneralManagements.objects.all()
permission_classes = (IsAuthenticatedOrReadOnly,)
renderer_classes = (GeneralManagementJSONRenderer,)
serializer_class = GeneralManagementSerializer
def get_queryset(self):
return GeneralManagements.objects.all()
def list(self, request):
queryset = self.get_queryset()
page = self.paginate_queryset(queryset)
print("request ", request)
serializer_context = {'request': request}
serializer = self.serializer_class(
page, context=serializer_context, many=True
)
print("serializer ", serializer, "serializer.data", serializer.data )
return self.get_paginated_response(serializer.data)
You should call paginate_queryset before calling get_paginated_response
Note that the paginate_queryset method may set state on the pagination instance, that may later be used by the get_paginated_response method.
https://www.django-rest-framework.org/api-guide/pagination/
I am just adding my answer to help other users with the same problem they are facing.
Adding to the above statement, it also has a solution to your question in a simpler way.
Just pass PageNumberPagination and add request in self.paginate_queryset method.
class PaginatedProductList(APIView, PageNumberPagination):
def get(self, request):
products = Product.objects.filter(....)
return self.paginate_queryset(products, request)
So finally I found out how to solve this problem..
Below is the code(Simple and silly mistakes that I was doing)
class PaginatedProductList(APIView, PageNumberPagination):
page_size = 1000 #---crucial line
max_page_size = 1000
def get_paginated_response(self, data, page, page_num):
return Response(OrderedDict([
('count', self.page.paginator.count),
('current', page),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('page_size', page_num),
('results', data)
]))
def get_queryset(self, request):
product_sync_ts = self.request.GET.get('product_sync_ts', None)
if product_sync_ts:
product = Product.objects.filter(...)
)
return self.paginate_queryset(product, self.request)
raise APIException400(request, {'details': "Bad Request"})
def get(self, request):
page = self.request.GET.get('page', 1)
page_size = self.request.GET.get('page_size', 1000)
products = self.get_queryset(request)
serializer = SyncedProductSerializer(instance={'products': products})
return self.get_paginated_response(serializer.data, page, page_size)
Other than inheriting PageNumberPagination class in view, try defining your pagination class outside your view(as a separate class) inheriting from PageNumberPagination. and mention that class name as pagination class = YourClassName. inside your view
class PaginationClass(PageNumberPagination):
page_size = 2
and in view,
class GeneralManagementAPIView(generics.ListAPIView):
pagination_class = PaginationClass
This is my ViewSet:
class PostViewSet(viewsets.ModelViewSet):
serializer_class = PostSerializer
permission_classes = (IsAuthenticated, IsOwnerDeleteOrReadOnly)
def get_queryset(self):
return Post.objects.filter(location=self.request.user.userextended.location)
def perform_create(self, serializer):
serializer.save(owner=self.request.user, location=self.request.user.userextended.location)
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'format': self.format_kwarg,
'view': self,
'location': self.request.user.userextended.location
}
#detail_route(methods=['post'], permission_classes=[IsAuthenticated, IsFromLocation])
def like(self, request, pk=None):
post = self.get_object()
post.usersVoted.add(request.user)
return Response(status=status.HTTP_204_NO_CONTENT)
#detail_route(methods=['get'], permission_classes=[IsAuthenticated, ValidPostPkInKwargs, IsFromPostLocation])
def replies(self, request, pk=None):
post = self.get_object()
replies = post.postreply_set.all()
serializer = PostReplySerializer(replies, many=True)
return Response(serializer.data)
And this is my PostReplySerializer:
class PostReplySerializer(serializers.ModelSerializer):
owner = serializers.SlugRelatedField(slug_field='username', read_only=True)
voted = serializers.SerializerMethodField()
def get_voted(self, obj):
return self.context['request'].user in obj.usersVoted.all()
class Meta:
model = PostReply
fields = ('id', 'owner', 'post', 'voted', 'location')
The error points to the line
return self.context['request'].user in obj.usersVoted.all()
and says:
KeyError at /URL/20/replies/
'request'
Any idea why DRF says 'request' is a key error even though (from my understanding) it should be automatically in self.context?
Note that PostViewSet works perfectly fine for all other requests (if I get a Post, get a list of posts etc.). It just doesn't work for replies.
It's not in self.context because you have overridden get_serializer_context. request object is attached to context via this method. Just add request: self.request in your return statement of get_serializer_context that would solve the problem. Take a look at default implementation of get_serializer_context here https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/generics.py to understand more. Hope it helps..
EDIT
Since you are using different serializer(PostReplySerializer) in detail_route, you need to create serializer instance like serializer = PostReplySerializer(replies, many=True, context={'request': self.request})
I'm using the Django rest framework. I need to get the user on views.py but I not able to.
from app.models import SmsToSend
from app.serializers import SmsToSendSerializer
from rest_framework import generics
from app.permissions import IsOwner
from rest_framework import permissions
class SmsToSendList(generics.ListCreateAPIView):
queryset = SmsToSend.objects.all()
serializer_class = SmsToSendSerializer
permission_classes = (IsOwner, permissions.IsAuthenticated)
def pre_save(self, obj):
obj.owner = self.request.user
How can I call request.user here?
Best Regards,
You are very close. I think a lot of people spend time trying to figure this out. Define request as a parameter in your view method and you will have access to it like this.
def pre_save(self, request, obj):
obj.owner = request.user
You can get your queries like this.
request.REQUEST.get('<query>')
In a serializer method it is slightly different, you can get data like this.
request = self.context['request']
user = request.user
query = request.GET['<query>']
Hope this is helpful!
class SmsToSendList(generics.ListCreateAPIView):
#queryset = SmsToSend.objects.all()
serializer_class = SmsToSendSerializer
permission_classes = (IsOwner, permissions.IsAuthenticated)
def get_queryset(self):
user = self.request.user
return SmsToSend.objects.filter(owner=user)
def pre_save(self, obj):
obj.owner = self.request.user
Instead of the queryset I had to use get_queryset method
def get_queryset(self, *args, **kwargs):
user_id = self.request.user.id