Calling DRF api within another view in django 2.2 - python

I have an api view as:
class part_detail(generics.RetrieveUpdateDestroyAPIView):
queryset = parts.objects.all()
serializer_class = parts_serializer
I want to pass this as context in a detail view. Currently I am doing it as
def part_detail(request, id):
context = requests.get('http://localhost:8000/bon/part_detail/'+id+'/?format=json').json()
return render(request, 'frontend/part_detail.html',context)
But this will obliviously not work in production. How can I correctly call in apiview directly.

Related

Can not switch from assigning permission_classes to use decorator #permission_classes

The below is an api that required authen. It works
class some_random_api(generics.GenericAPIView):
permission_classes = (IsAuthenticated, )
def get(self,request):
return HttpResponse("Called successfully")
However, I dont like declaring variable. After looking up this document, https://www.django-rest-framework.org/api-guide/permissions/ . I find an alternative way by using decorator. So I change my code into this.
from rest_framework.decorators import permission_classes
class some_random_api(generics.GenericAPIView):
#permission_classes(IsAuthenticated)
def get(self,request):
return HttpResponse("You call random test api")
Now this API does not check Authen
The decorator #permission_classes is only applicable to function-based API views as documented.
REST framework provides a set of additional decorators which can be added to your views. These must come after (below) the #api_view decorator.
The available decorators are:
...
#permission_classes(...)
...
Also here:
Or, if you're using the #api_view decorator with function based views.
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def example_view(request, format=None):
...
An alternative to defining a fixed list permission_classes = (IsAuthenticated, ) is to override the get_permissions() and assign different permissions for the different HTTP methods as described here.
class some_random_api(generics.GenericAPIView):
def get_permissions(self):
if self.request.method == "GET": # If using viewsets, the self.action can be used e.g. <if self.action == "retrieve":>
permission_classes = [permissions.IsAuthenticated]
else:
permission_classes = [permissions.IsAdminUser]
return [permission() for permission in permission_classes]
def get(self, request):
return HttpResponse("You call random test api")
Related questions:
Django Rest Framework - GenericViewSet with Authentication/Permission decorator
Django REST Framework - Separate permissions per methods

Why does `HyperlinkedRelatedField` in Django rest framework needs its view to return `request` paramater as context?

I'm new to DRF. While defining a HyperlinkedRelatedField in serializer class like this:
class JournalistSerializer(serializers.ModelSerializer):
articles = serializers.HyperlinkedRelatedField(view_name="article-
detail")
im getting the following error:
`HyperlinkedRelatedField` requires the request in the serializer
context. Add `context={'request': request}` when instantiating the
serializer.
when i add context={'request': request} in the related APIView class:
class JournalistListCreateAPIView(APIView):
def get(self,request):
journalist = Journalist.objects.all()
serializer = JournalistSerializer(journalist,many=True,context=
{'request':request})
return Response(serializer.data)
the HyperLink in the APIView works fine. But i dont understand why request has to be sent while instantiating the serializer. Please help me understand.
It does require request in context as it builds absolute URL
to be more concrete it is used get_url serializer method
def get_url(self, obj, view_name, request, format):
...
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)

Djangorest framework same Generic Create View with GET and POST

I'm using a Generic CreateAPIView to save a model in the database. Here's my code:
class AppointmentCreateAPIView(generics.CreateAPIView):
permission_classes = (AppointmentCreatePermission,)
queryset = Appointment.objects.all()
serializer_class = AppointmentSerializer
And in my urls.py file, I have this:
urlpatterns[
url(r'^appointments/create', AppointmentCreateAPIView.as_view()),
]
This url obviously supports the POST operation. However, I want to use this same url to handle a GET request, which would fetch the data necessary to populate the appointment creation form. I understand that I can use separate urls for get and post, but that's not what I'm looking for. Is it possible that I keep the same url, but with different HTTP Verb, the view would be able to handle both GET and POST request?
You can do this by manually adding get method to your view, it would look something like this. Code below probably will not work, but will give you general idea.
from rest_framework.response import Response
class AppointmentCreateAPIView(generics.CreateAPIView):
permission_classes = (AppointmentCreatePermission,)
queryset = Appointment.objects.all()
serializer_class = AppointmentSerializer
def get(self, request, *args, **kwargs):
serializer = AppointmentSerializer({your_data})
return Response(serializer.data)

Dynamically Change Authentication Classes Django Rest Framework

I understand that we can set up authentication classes in class based viewsets like this:
class ExampleViewSet(ModelViewSet):
authentication_classes = (SessionAuthentication, BasicAuthentication)
However, is there a way to dynamically change the authentication class based on the request method? I tried overriding this function in my ExampleViewSet:
def get_authenticators(self): # Found in
if self.request.method == "POST":
authentication_classes.append(authentication.MyCustomAuthentication)
return authentication_classes
However, django rest does not have the request object setup at this point:
'ExampleViewSet' object has no attribute 'request'
Note: not real variable names - just for example purpose.
Based on the previous answer, it works on django 1.10
#detail_route(methods=['post', 'get'])
def get_authenticators(self):
if self.request.method == "GET":
self.authentication_classes = [CustomAuthenticationClass]
return [auth() for auth in self.authentication_classes]
You can use detail_route decorator from rest_framework like this for getting requests,
detail_route can be used to define post as well as get,options or delete options
So,the updated code should be like :
from rest_framework.decorators import detail_route
class ExampleViewSet(ModelViewSet):
authentication_classes = (SessionAuthentication, BasicAuthentication)
#detail_route(methods=['post','get'])
def get_authenticators(self, request, **kwargs): # Found in
if request.method == "POST":
authentication_classes.append(authentication.MyCustomAuthentication)
return authentication_classes
For further reading,Read from here.

Django: Extend context of class based view with Admin context

I have a class based view which just displays a list of configurations.
This view is added to the Django Admin site by using the following code:
#admin.register(ZbxHostConf)
class ZbxHostConfListViewAdmin(admin.ModelAdmin):
review_template = 'admin/admzbxhostconf_list.html'
def get_urls(self):
urls = super(ZbxHostConfListViewAdmin, self).get_urls()
my_urls = patterns('',
(r'^zbxhostconflist/$', self.admin_site.admin_view(self.review)),
)
return my_urls + urls
def review(self, request):
return ZbxHostConfListView.as_view()(request)
The template extends the admin/base_site.html template. I can access the site only after I log in to the Django Admin site. Unfortunately the template cannot access the context data provided by the admin view.
As the Django documentation suggests the context data will be provided directly to the TemplateResponse function:
def my_view(self, request):
# ...
context = dict(
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
# Anything else you want in the context...
key=value,
)
return TemplateResponse(request, "sometemplate.html", context)
For function-based views there is the possibility of the extra_context argument but class-based views don't provide this argument. I guess I have to modify the get_context_data function but I don't really understand how I can provide the admin context data to the get_context_data function of my class based view. Any suggestions?
This might not be a correct answer, but I believed you could try something like this.
#!/usr/bin/python3
from django.contrib import admin
class MyTemplateView(TemplateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(admin.site.each_context(self.request))
return context

Categories

Resources