DetailApiViewset with classed based api view - python

I am trying to create detail API viewset but for now, I am getting page not found whenever I go to my "matches/api/matches/1/". ListCreateAPIView works fine.
Here are my viewsets:
class MatchViewset(viewsets.ViewSetMixin, generics.ListCreateAPIView):
serializer_class = MatchSerializer
def get_queryset(self):
header_token = self.request.META.get('HTTP_AUTHORIZATION', None)
print(header_token)
if header_token is not None:
try:
token = sub('Token ', '', self.request.META.get('HTTP_AUTHORIZATION', None))
token_obj = Token.objects.get(key=token)
self.request.user = token_obj.user
except Token.DoesNotExist:
pass
print(self.request.user)
return Match.objects.filter(creator=self.request.user)
class MatchDetailViewset(generics.RetrieveUpdateDestroyAPIView):
queryset = Match.objects.all()
serializer_class = MatchSerializer
and routers:
router = routers.DefaultRouter()
router.register(r'matches', matches_views.MatchViewset, base_name="matches")
and urls:
app_name = 'matches'
urlpatterns = [
path('api/', include(router.urls)),
]

According to the docs here: Routers usage
after the router.register(r'matches', matches_views.MatchViewset, base_name="matches") you must give
urlpatterns = router.urls
I guess this would solve the issue

The MatchDetailViewset is not registered in urlpatterns, that's why you're getting a 404 error
It seems like DRF router not support registering multiple viewset with the same prefix.
So maybe you should try something like this:
class MatchViewSet(viewsets.ModelViewSet):
serializer_class = MatchSerializer
queryset = Match.objects.all()
def list(self, request, *args, **kwargs):
header_token = self.request.META.get('HTTP_AUTHORIZATION', None)
print(header_token)
if header_token is not None:
try:
token = sub('Token ', '', self.request.META.get('HTTP_AUTHORIZATION', None))
token_obj = Token.objects.get(key=token)
self.request.user = token_obj.user
except Token.DoesNotExist:
pass
print(self.request.user)
# customize the queryset for listview
queryset = self.get_queryset().filter(creator=self.request.user)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

Related

Django Viewset retrieve not working with Default Router

I am trying to access a specific comment using the retrieve method in Django View sets. I am using a default router in order to route my urls. I am able to list all comments at api/posts/, but am unable to get a single comment at api/posts/1. I am getting a type error: Field.init() got an unexpected keyword argument 'pk' when trying to access the URL. Any ideas as to why?
urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from posts.views import PostsViewSet, CommentsViewSet
router = DefaultRouter()
router.register(r"comments", CommentsViewSet, basename='comments')
urlpatterns = [
path("", include(router.urls)),
]
views.py
class CommentSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(label='commentID')
comment = serializer.CharField()
created_at = serializers.DateTimeField(required=False)
updated_at = serializers.DateTimeField(required=False)
posts = serializers.SerializerMethodField()
class Meta:
model = Comments
# fields = "__all__"
fields = ['id', 'comment','created_at', 'updated_at', 'posts']
def to_representation(self, instance: Comment) -> dict:
'''Pass for now'''
ret = super().to_representation(instance)
return ret
def get_queryset(self) -> QuerySet:
qs = Comment.objects.all()
return qs
def create(self, validated_data: dict) -> Comment:
return Comment.objects.create(**validated_data)
def update(self, instance: Comment, validated_data: dict) -> Comment:
'''Pass post-validation errors silently'''
for field in validated_data:
setattr(instance, field, validated_data.get(
field, getattr(instance, field)))
instance.save()
return instance
class CommentViewSet(viewsets.ViewSet):
def list(self, request):
queryset = Comment.objects.all()
result = CommentSerializer(queryset, many=True)
if result:
return Response(result.data)
else:
return Response(data=result.data, status=200)
def retrieve(self, request, pk=None):
queryset = Comment.objects.all()
condition = get_object_or_404(queryset, pk=pk)
result = CommentSerializer(queryset, pk=pk)
print(result)
return Response(result.data)
First you are not using the condition object in serializer.
Second drf default pk field name is id not pk and no need to pass pk during serialization process.Below is updated retrieve method kindly check the same.
def retrieve(self, request, pk=None):
# queryset = Comment.objects.all() #no need as you are using get_object_or_404 to fetch single object
condition = get_object_or_404(Comment, id=pk) #replaced pk by id here
result = StudentSerializer(condition) #used condition in serializer
print(result)
return Response(result.data)

Django Reversion - How to use With Django Rest

I'm trying to use Django Reversion with my django-rest, but i still confuse about it or i just couldn't what i want in Document.
Here what i tried
Settings
INSTALLED_APPS = [
....
'reversion'
]
MIDDLEWARE = [
'reversion.middleware.RevisionMiddleware'
]
In Model
#reversion.register()
class History(models.Model):
pass
In ModelViewset
from reversion.views import RevisionMixin
class HistoryViewset(RevisionMixin, viewsets.ModelViewSet):
queryset = History.objects.all()
serializer_class = HistorySerializer
filter_backends = (filters.DjangoFilterBackend,)
# if pagination page = none, it will return all page
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if 'page' in request.query_params:
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
Then i try to update My Model and try to GET request from api endpoint, i got null Value.
What do i Missing???
I'll appreciate of all ur Help. Thanks...

Pagination does't work for my Django rest framework project and I'm using generic-views

I have tried many options, but pagination still doesn't work. I'm using generic-views and code like this:
class ListFood(generics.ListAPIView):
queryset = Food.objects.all()
serializer_class = FoodSerializer
def list(self,request):
queryset = self.get_queryset()
serializer = FoodSerializer(queryset, many=True)
return Response(serializer.data)
and in settings.py, I have written this:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS':'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20
}
I have tried to modify particular aspects of the pagination style, such as:
class StandardResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = 'page_size'
max_page_size = 1000
class ListFood(generics.ListAPIView):
queryset = Food.objects.all()
serializer_class = FoodSerializer
pagination_class = LargeResultsSetPagination
def list(self,request):
queryset = self.get_queryset()
serializer = FoodSerializer(queryset, many=True)
return Response(serializer.data)
but it still didn't work.
My urls.py is:
app_name = "lab"
urlpatterns = [
re_path('^food/$', ListFood.as_view(), name="listfood"),
]
There is no error message, but when I request the URL http://127.0.0.1:8000/api/food/?page=1 or http://127.0.0.1:8000/api/food/?page=2
it's still not paginated. Django gives me 2000 pieces of data in JSON.
Original list implementation paginates response:
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
Your class overrides list with custom implementation, that is why it does not return paginated response. Just don't override list.

Django Rest required parameters in URL

I'm using django rest framework.
Here is my code:
urls.py:
urlpatterns = [
url(r'^users/show', UserShow.as_view()),
]
view.py:
class UserShow(ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get_queryset(self):
queryset = User.objects.all()
username = self.request.query_params.get('username', None)
user_id = self.request.query_params.get('user_id', None)
if username is not None:
queryset = queryset.filter(username=username)
if user_id is not None:
queryset = queryset.filter(pk=user_id)
return queryset
I want to get values from url like this:
/users/show?user_id=1 or /users/show?username=mike.
Either an user_id or username must be required parameter. How can I control it in class based views?
With my code if I'm sending the request with wrong parameter name /users/show?user111name=mike or simple /users/show the view of course response me with queryset = User.objects.all() and lists all the users. I don't need that. I need if required parameters are None response with 404.
I can get needed result with function based view:
#api_view(['GET'])
def users(request):
if request.method == 'GET':
queryset = User.objects.all()
username = request.GET.get('username', None)
user_id = request.GET.get('user_id', None)
if username is not None:
queryset = queryset.filter(username=username)
elif user_id is not None:
queryset = queryset.filter(pk=user_id)
else:
return Response({"status": "required field not found."},
status=status.HTTP_404_NOT_FOUND)
if not queryset.exists():
return Response({"status": "not found."},
status=status.HTTP_404_NOT_FOUND)
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
But how can I do it with generic class based views?
class UserIdRetrieve(RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserUsernameRetrieve(UserIdRetrieve):
lookup_field = 'username'
and in urls:
urlpatterns = [
url(r'^users/(?P<pk>\d+)/', UserIdRetrieve.as_view()),
url(r'^users/by-username/(?P<username>\w+)/', UserUsernameRetrieve.as_view())
]
if your url structure is a must, small change to above:
class UserIdRetrieve(RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
if 'username' in self.request.query_params:
filter_kwargs = {'username': self.request.query_params['username']}
elif 'user_id' in self.request.query_params:
filter_kwargs = {'id': self.request.query_params['user_id']}
else:
raise Http404('Missing required parameters')
obj = get_object_or_404(queryset, **filter_kwargs)
# May raise a permission denied
self.check_object_permissions(self.request, obj)
return obj
and in urls:
urlpatterns = [
url(r'^users/show', UserRetrieve.as_view())
]
class UserShow(ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def filter_queryset(self, queryset):
username = self.request.query_params.get('username', None)
user_id = self.request.query_params.get('user_id', None)
if username is not None:
queryset = queryset.filter(username=username)
if user_id is not None:
queryset = queryset.filter(pk=user_id)
return queryset
def list(self,request,*args,**kwargs):
username = self.request.query_params.get('username', None)
user_id = self.request.query_params.get('user_id', None)
if not (username or user_id):
return Response({"status": "Required field not found."},
status=status.HTTP_404_NOT_FOUND)
return super(UserShow, self).list(request,*args,**kwargs)

Django rest framework - hyperlinking non-model serializer fields

I'm struggling to figure out how to implement the Hyperlinked relationships for non-model querysets. I have a viewset:
class GGGViewSet(viewsets.ViewSet):
def list(self, request):
serializer_class = manufacture_serializer(ar)
serializer = serializer_class(
instance = sample.values(), many=True
)
return Response(serializer.data)
def retrieve(self, request, pk=None):
try:
anobject = sample[pk]
except KeyError:
return Response(status=status.HTTP_404_NOT_FOUND)
except ValueError:
return Response(status=status.HTTP_400_BAD_REQUEST)
serializer_class = manufacture_serializer(ar)
serializer = serializer_class(instance=anobject)
return Response(serializer.data)
I am trying to get the value resource at /data/trait/ to be rendered as a link, where:
trait-list
data/trait/
{
"value": 12334,
"another_value": 45672,
}
trait-detail
data/trait/value/
{
"value":12334
}
Attempted:
url = serializers.HyperlinkedIdentityField(view_name='trait-list')
Error: AttributeError at /asvo/data/trait/ 'AObj' object has no attribute 'pk'.
Any ideas on the best way to approach this would be appreciated. :)
You were probably quite close. Based on the information provided, here's something that demonstrates HyperlinkedIdentityField usage without relying on an actual Django model. I had to use my imagination when filling in the details of your architecture.
from rest_framework import routers
from rest_framework import serializers
from rest_framework import status
from rest_framework import viewsets
from rest_framework.response import Response
# This goes in the URL routing file
router = routers.DefaultRouter()
router.register(r'trait', GGGViewSet, base_name='trait')
urlpatterns = router.urls
# The "model"
class Thing(object):
def __init__(self, pk, value, another_value):
self.pk = pk
self.value = value
self.another_value = another_value
# The "queryset"
sample = {
'1': Thing(1, 12334, 45672),
'2': Thing(2, 12335, 45673),
'3': Thing(3, 12336, 45674)
}
# The serializer
class manufacture_serializer(serializers.Serializer):
pk = serializers.HyperlinkedIdentityField(
view_name='trait-detail', read_only=True)
value = serializers.IntegerField()
another_value = serializers.IntegerField()
class Meta:
fields = ['pk', 'value', 'another_value']
# The view
class GGGViewSet(viewsets.ViewSet):
def list(self, request):
serializer = manufacture_serializer(
instance=sample.values(), many=True, context={'request': request})
return Response(serializer.data)
def retrieve(self, request, pk=None):
try:
anobject = sample[pk]
except KeyError:
return Response(status=status.HTTP_404_NOT_FOUND)
except ValueError:
return Response(status=status.HTTP_400_BAD_REQUEST)
serializer = manufacture_serializer(
instance=anobject, context={'request': request})
return Response(serializer.data)
I did not fully understand the second half of the question regarding the data/trait/ and data/trait/value/, but hopefully this is enough to further you along.
Cheers!

Categories