how to get a string parametr in drf modelviewset - python-3.x

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)

Related

How to add pagination : super()

I am trying to add pagination using super().list() method in modelviewset
class RecentlyViewedVideosViewSet(ResponseViewMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = RecentlyViewedVideos.objects.all()
serializer_class = RecentlyViewedVideosSerializer
def list(self, request, **kwargs):
print('list')
try:
if 'learner_id' in self.kwargs:
learner_id = self.kwargs['learner_id']
else:
learner_id = self.request.learner.id
response_data = super().get_queryset().filter(learner_id=learner_id)
print(response_data)
serializer = RecentlyViewedVideosSerializer(response_data, many=True)
return self.jp_response(s_code='HTTP_200_OK', data=serializer.data)
in output, it displays all the documents in the table, but I only need those details in the "details", give me a way to get the exact output.
It might be better to do this in the .get_queryset(…) method:
def get_queryset(self):
if 'learner_id' in self.kwargs:
learner_id = self.kwargs['learner_id']
else:
learner_id = self.request.learner.id
return super().get_queryset().filter(learner_id=learner_id)
then the boilerplate code to filter, paginate, etc. the view are still implemented by the .list(…) method of the ListModelMixin.

Django Rest Framework DELETE request responds like a GET request

I'm trying to delete an entry in my data base that is returned by a modelviewset get_queryset. When sending a DELETE request through the DRF web interface and via postman, I receive this response "DELETE /api/remove_self/3 HTTP/1.1" 200 along with the data I am trying to delete. The code that gives this result looks like this:
Models.py
class EventAtendee(models.Model):
"""Lists users atending an event"""
#below connects user profile to event
id = models.AutoField(primary_key=True)
event_id = models.IntegerField(null = True)
user_profile = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
return self.event_id
views.py
class RemoveSelfFromEvent(viewsets.ModelViewSet):
"""Remove Yourself From an Event you were attending"""
authentication_classes = (TokenAuthentication,)
serializer_class = serializers.EventAtendeeSerializer
permission_classes = (permissions.UpdateOwnStatus, IsAuthenticated)
def perform_create(self, serializer):
"""Sets the user profile to the logged in user"""
#
serializer.save(user_profile=self.request.user)
def get_queryset(self):
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
#user_profile = self.kwargs['user_profile']
event_id = self.kwargs['event_id']
return models.EventAtendee.objects.filter(event_id=event_id, user_profile=self.request.user)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
urls.py
router = DefaultRouter(trailing_slash=False)
router.register('events', views.EventAtendeeViewSet, basename='EventAtendee')
urlpatterns = [
path('remove_self/<event_id>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'list'})),
]
Any help is much appreciated!
You are mapping the method DELETE to list in your urls.
path('remove_self/<event_id>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'list'})),
Correct way to do:
path('remove_self/<pk>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'destroy'})),
mapping of various methods:
POST : create
GET : retrieve
PUT : update
PATCH : partial_update
DELETE : destroy

How to get a request object from inside the generic.ListAPIView class for django-filter?

I have a django-filter query running using djangorestframework. The below view function is used for url. But when I get objects at the starting, I want to filter them not only by the parameters the search query has which are username and userid. But I also want to filter based upon who is logged in, which I can get through request object coming from URL.
The function getUsername() works independently but not with other code.
Hence is there a way to access self request in below code. Any help is greatly appreciated.
class userSearch(generics.ListAPIView):
def getUsername(self):
return self.kwargs['username']
serializer_class = UserSerializer
queryset = UserProfile.objects.filter(professor=User.objects.get(username=self.getUsername()).id).order_by('username')
filter_backends = (DjangoFilterBackend,SearchFilter)
filter_fields = (username,userid,userType)
search_fields = ('username', 'first_name')
Instead of defining the queryset attribute directly, you can override the get_queryset(self) method:
class userSearch(generics.ListAPIView):
serializer_class = UserSerializer
filter_backends = (DjangoFilterBackend, SearchFilter)
filter_fields = ('username', 'userid')
search_fields = ('username', 'first_name')
def get_queryset(self):
username = self.kwargs['username']
professor = User.objects.get(username=username)
# Here you can do the following thing:
current_user = self.request.user
# And use it as you wish in the filtering below:
return UserProfile.objects.filter(professor=professor).order_by('username')

How to implement django admin queryset filter with from extended user model class

I have extended Django default User model (just to save user state_id) class with following model.
class UserProfileInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,)
state_id = models.IntegerField(blank=False)
def __str__(self):
return self.user.username
And now I want to filter the data by logged user's state_id. I tried to implement queryset filter but it does not do anything.
class VisVisitsAdmin(admin.ModelAdmin):
list_per_page = 10
list_display = ('visit_id','visit_no','user_name','mobile_number','program_name','state_name','district_name','block_name','school_name',)
list_filter = ('date_of_visit',)
def queryset(self, request):
qs = super(VisVisitsAdmin, self).get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(state_id=request.user.UserProfileInfo.state_id)
def state_name(self, obj):
if obj.school_program:
return obj.school_program.school.cluster.block.district.state.name_of_state
state_name.short_description = 'state name'
You are trying to fetch the state_id from the userprofileinfo instance related to user object.
Everything seems fine but the instance is available as userprofileinfo and not UserProfileInfo , so change qs as :
qs.filter(state_id=request.user.userprofileinfo.state_id)

Django RestFramework call the Api by the Field

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!

Resources