Django Rest API merging delete/get/update/get methond in two class - django

At first you see my 4 method class in view.py:
class ContactList(ListAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializers
# This is delete method
class ContactDelete(DestroyAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializers
lookup_field = 'pk'
#below is post method to create new contact
class ContactCreate(CreateAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializers
#below is put and patch method to update contact
class ContactUpdate(UpdateAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializers
lookup_field = 'pk'
I want ContactList and ContactCreate should be in one class
and ContactDelete and ContactUpdate should be in one class
i am not getting how to merge it, can anyone tell me how to do it?
Note: i dont want APIViewSet

DRF has already to classes for that purpose. You can check them here and here
from rest_framework.generics import ListCreateAPIView, RetrieveDestroyAPIView
class ContactCreateListAPIView(ListCreateAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializers
class ContactRetrieveDeleteAPIView(RetrieveDestroyAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializers
lookup_field = 'pk'

Hope this helps
# This is create and list method
class ContactListCreate(ListAPIView, CreateAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializers
# This is delete and update method
class ContactDeleteUpdate(DestroyAPIView, UpdateAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializers
You can remove lookup_field = 'pk' from the view, since DRF took pk as the default value.

Related

Optimize getting the first record in a table using an API endpoint with Django REST Framework and/or Django-filter

I'm trying to retrieve the first record in a table using the endpoint below (please suggest if there's a more sensible URL convention).
http://127.0.0.1:8000/api/review/?first
The view I have works, but I'm hoping to refactor it because it smells.
class ReviewViewSet(ModelViewSet):
filter_backends = (DjangoFilterBackend, OrderingFilter)
serializer_class = ReviewSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
first = self.request.query_params.get('first')
queryset = RecordReview.objects.all()
if first is not None:
id_list = queryset.values_list('id')
first_item = id_list.order_by('id').first()
first_id = first_item[0]
queryset = queryset.filter(id=first_id)
return queryset
When I attempted to filter the queryset directly, I got errors like:
TypeError: object of type 'RecordReview' has no len()
The error comes from this line :
first_id = first_item[0]
This is because first_item is already a RecordReview, as it was retrieved using first()
You can simplify get_queryset as follows though :
class ReviewViewSet(ModelViewSet):
filter_backends = (DjangoFilterBackend, OrderingFilter)
serializer_class = ReviewSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
first = self.request.query_params.get('first')
queryset = RecordReview.objects.all()
if first is not None:
queryset = queryset.order_by('id')[:1]
return queryset

How to filter on date in Django Rest Framework

I wrote the following code, trying to filter on dates using DRF:
class FixtureFilter(django_filters.FilterSet):
date = django_filters.DateFilter('date__date', lookup_expr='exact')
class Meta:
model = Fixture
fields = ['date']
class FixtureViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Fixture.objects.all().order_by('-date')
serializer_class = FixtureSerializer
permission_classes = [permissions.IsAuthenticated]
filter_class = FixtureFilter
When I make a call to the API like http://localhost:8000/api/v1/fixtures?date=2021-11-29 it returns me more than 1 object whereas it should just return 1 object.
How do I implement this properly?
I believe you must add filter_backends field to FixtureViewSet to get it working, how documentation describes. Also, don't forget to update INSTALLED_APPS with django_filter as well. The corrected version would be:
from django_filters import rest_framework as filter
class FixtureFilter(django_filters.FilterSet):
date = django_filters.DateFilter('date', lookup_expr='exact')
class Meta:
model = Fixture
fields = ['date']
class FixtureViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Fixture.objects.all().order_by('-date')
serializer_class = FixtureSerializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = (filters.DjangoFilterBackend,)
filter_class = FixtureFilter

RetrieveUpdateDestroy and get_queryset how works

i am learning drf and i little confused
in the urls.py i have
path('todos/<int:pk>', views.TodoRetrieveUpdateDestroy.as_view()),
on the views.py
class TodoRetrieveUpdateDestroy(generics.RetrieveUpdateDestroyAPIView):
serializer_class = TodoSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
user = self.request.user
return Todo.objects.filter(user=user)
by logic i would add to filter like pk = self.kwargs[‘pk’] to send only one element Todo but it works and send only that ‘id=pk’ post without adding additional filter.Can u explain why please and how works RetrieveUpdateDestroy and get_queryset)
RetrieveUpdateDestroyAPIView doesnt execuate method def get_queryset(self): in the first place
It has def get_object(self): method which gets object by lookup_fields and query from query set method returned data again
So to get/update/delte single data,
You have to do like this:
class TodoRetrieveUpdateDestroy(generics.RetrieveUpdateDestroyAPIView):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
permission_classes = [permissions.IsAuthenticated]
lookup_field = 'pk'
and your urls should be like this:
path('some-paht/<int:pk>/', TodoRetrieveUpdateDestroy.as_view(), name='some_name')

I applied filterset in drf. i didn't know why all the data is returned when i query with a field not in filterset

I don't know why all data is returned when I query with a field that not in FilterSet class
This is my model
class TempModel(models.Model):
md5 = models.CharField()
sha1 = models.CharField()
and following is my filterSet class
class TempFilter(filters.FilterSet):
class Meta:
model = TempModel
fields = ("md5")
and finally this is my ViewSet
class TempViewSet(viewsets.ModelViewSet):
queryset = TempModel.objects.all()
permission_classes = [IsAuthenticated]
authentication_classes = [TokenAuthentication]
serializer_class = TempSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = TempFilter
When I make a request
/temp/?md5=XXXX, it works very well, but /temp/?sha1=XXXX, it returns all data.
I think if request not specified fields, it returns not found.
I try to define exclude in FilterSet class, but it still not working, How will I solve that problem?
I found out in the django-filters documentation that you can override qs property in order to filter the primary queryset (the queryset = TempModel.objects.all() you declared in the viewset).
class TempFilter(filters.FilterSet):
class Meta:
model = TempModel
fields = ("md5")
#property
def qs(self):
queryset = super(TempModel, self).qs
query_params = self.request.query_params
if any(query_param not in TempModel.Meta.fields for query_param in query_params):
return queryset.none()
return queryset
So the code above would return empty queryset if any of the query parameters didn't exist.

django-rest-framework How to handle multiple URL parameter?

How can I use generic views with multiple URL parameters? Like
GET /author/{author_id}/book/{book_id}
class Book(generics.RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
lookup_field = 'book_id'
lookup_url_kwarg = 'book_id'
# lookup_field = 'author_id' for author
# lookup_url_kwarg = 'author_id'
Just add a little custom Mixin:
in urls.py:
...
path('/author/<int:author_id>/book/<int:book_id>', views.Book.as_view()),
...
in views.py:
Adapted from example in the DRF documentation:
class MultipleFieldLookupMixin:
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
multi_filter = {field: self.kwargs[field] for field in self.lookup_fields}
obj = get_object_or_404(queryset, **multi_filter) # Lookup the object
self.check_object_permissions(self.request, obj)
return obj
class Book(MultipleFieldLookupMixin, generics.RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
lookup_fields = ['author_id', 'book_id'] # possible thanks to custom Mixin
Might be late to the party here, but this is what I do:
class Book(generics.RetrieveAPIView):
serializer_class = BookSerializer
def get_queryset(self):
book_id = self.kwargs['book_id']
author_id = self.kwargs['author_id']
return Book.objects.filter(Book = book_id, Author = author_id)
You'll need to use named groups in your URL structure and possibly override the get() method of your view.