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)
Related
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)
I have a simple rest api which I want to send a post request to using requests.
My url pattern is this:
url(r'^$', views.ProductList.as_view())
Inside my view I have:
class ProductList(generics.ListAPIView):
serializer_class = ProductSerializer
def post(self, request, format=None):
print('THIS IS A POST REQUEST')
queryset = [product.name for product in Product.objects.all()]
return Response(queryset)
And I am trying to send a post request using:
response = requests.post('http://127.0.0.1:8080/')
However this returns a 403, and the print statement isn't printed. I have done some research and I think it may have something to do with the CSRF token not being there but i'm not to sure how to add that. Does anybody know how I can get the post request to work?
I'm using python 3.6.3 and Django 1.10
ListAPIView is meant for only listing your products hence the POST requests are forbidden.
ListAPIView
Used for read-only endpoints to represent a collection of model instances.
taken from Django Rest Framework documentation
You should use ListCreateAPIView:
class ProductList(generics.ListCreateAPIView):
"""
List all products or create a product.
"""
queryset = Product.objects.all()
serializer_class = ProductSerializer
I want to create two endpoints /comments/ and /comments/requests/ or something to that effect. The first shows your comments, and the second shows your pending comments (Comments that people sent you that you need to approve). They both work with a comments model. How could I achieve this in Django Rest Framework?
Right now, my view is
class CommentsListview(APIView):
serializer_class = CommentSerializer
def get(self, request, format=None):
comments, _, _, = Comments.get_comment_users(request.user)
comments_serializer = CommentSerializer(comments, many=True)
return Response({'comments': comments_serializer.data})
def requests(sel,f request, format=None):
_, requests, _ = Comments.get_comment_users(request.user)
requests_serializer = CommentSerializer(requests, many=True)
return Response({'requests': requests_serializer.data})
I'd like to allow a user to go to localhost:8000/comments/ to view their comments and localhost:8000/comments/requests/ to view their pending comment requests. Since I haven't been able to figure this out, the only other sollution would be to require the user to switch the behavior of the endpoint using a parameter as a flag /comments/?requests=True but that just seems sloppy.
use list_route decorator and genericviewset
from rest_framework import viewsets
from rest_framework.decorators import list_route
class CommentsListview(viewsets.GenericViewSet):
serializer_class = CommentSerializer
def list(self, request, format=None):
comments, _, _, = Comments.get_comment_users(request.user)
comments_serializer = CommentSerializer(comments, many=True)
return Response({'comments': comments_serializer.data})
#list_route()
def requests(sel,f request, format=None):
_, requests, _ = Comments.get_comment_users(request.user)
requests_serializer = CommentSerializer(requests, many=True)
return Response({'requests': requests_serializer.data})
/comments/ will call list method
/comments/requests/ will call requests method
also look at GenericViews and ViewSet docs it might be helpfull
I have a Serializer in my code like this
class SampleSerializer(serializers.ModelSerializer):
class Meta:
model = Model
and Viewset like this
class SampleViewSet(GenericAPIView):
serializer_class = SampleSerializer
def get(self, request, *args, **kwargs):
pass
def post(self, request, *args, **kwargs):
pass
def put(self, request, *args, **kwargs):
pass
I have url like this for this viewset
Url #1:
url(r'^sample/$', SampleViewSet.as_view())
This makes url for all methods I have in my viewset like get, post and put etc. I want to make separate url for my get method but using same serializer. This url will look like this
Url #2:
url(r'^sample/(?P<model_id>\d+)/$', SampleViewSet.as_view())
How can I do this using same Viewset and Serializer? When I write Url #2 in urls.py, Swagger shows me all three type (get, post and put) of methods for that Url.
You could use require_GET decorator from django.views.decorators.http for this, and use it in your URL config:
urlpatterns = [
url(r'^sample/$', SampleViewSet.as_view()),
url(r'^sample/(?P<model_id>\d+)/$', require_GET(SampleViewSet.as_view())),
]
for more fine tuning there is also a require_http_method decorator which receives allowed methods in its parameters, e.g.:
url(r'^sample/(?P<model_id>\d+)/$', require_http_method(['GET', 'DELETE'])(SampleViewSet.as_view()))
See https://docs.djangoproject.com/en/dev/topics/class-based-views/intro/#decorating-in-urlconf for details.
Why don't you inherit ViewSet from viewsets.ViewSet and map your urls view DefaultRouter?
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'sample', SampleViewSet)
urlpatterns = router.urls
It will handle all urls for your. /sample/:id now will be available for GET, PUT and DELETE methods.
Also if it plain CRUD for your Sample model, there is a better solution to use a viewsets.ModelViewset.
I need to execute an SSH command using a POST method. The command and its parameters are specified in the POST request’s JSON payload.
I have no idea on how to acompplish this using the DefaultRouter from django REST framework
So my first question is; How do I create a route or view for this url?
POST http://127.0.0.1/datacenter/<datacenter_id>/<server_id>/ssh/
And, how do I get the data from the payload in order to work with it?
I've tried with something like this;
#detail_route(methods=['POST'])
def ssh(self, request, pk=None):
print request.data
but Im getting "Expected a Response, HttpResponse or HttpStreamingResponse to be returned from the view, but received a <type 'NoneType'>"
models.py
class Datacenter(models.Model):
# Parent data
def __unicode__(self):
return self.name
class Servers(models.Model):
datacenter = models.ForeignKey(Datacenter)
def __unicode__(self):
return self.hostname
serializers.py
class ServerSerializer(serializers.ModelSerializer):
class Meta:
model = Server
class DatacenterSerializer(serializers.ModelSerializer):
servers = ServerSerializer(many=True)
class Meta:
model = Datacenter
fields = ('id', 'servers')
views.py
class DatacenterViewSet(viewsets.ModelViewSet):
queryset = Datacenter.objects.all()
serializer_class = DatacenterSerializer
class ServerViewSet(viewsets.ModelViewSet):
queryset = Server.objects.all()
serializer_class = ServerSerializer
urls.py
router = routers.DefaultRouter()
router.register(r'Datacenter', views.DatacenterViewSet)
urlpatterns = router.urls
Your current code seems to be nearly-complete. Assuming that you have a function that does the actual execution (let's call it "run_ssh_command"), a rudimentary version of your view could look something like this:
#detail_route(methods=['POST'])
def ssh(self, request):
input = json.loads(request.data) # I'd use a serializer here
output = run_ssh_command(input['command']) # or whatever the field name is
return Response(json.dumps({'result': output}),
content_type="application/json")
Some caveats:
Make sure you use proper authentication,
Keep in mind that some SSH commands might take a while to run OR they may just hang (E.G., waiting for input),
Take a look at http://www.django-rest-framework.org/tutorial/2-requests-and-responses/ for an example on how to use Serializers for request validation.