DRF - Method 'GET' not allowed - python

I'm trying to setup a class based view in Django Rest Framework.
This is my urls.py -
from django.conf.urls import patterns, include, url
from rest_framework.urlpatterns import format_suffix_patterns
from django.contrib import admin
from TidalDEV import views
admin.autodiscover()
urlpatterns = patterns('',
url(r'^test/(?P<pk>[0-9]+)/$', views.TESTXMLDetail.as_view()),
)
And this is my view -
import os, tempfile, zipfile
from django.shortcuts import render
from django.core import serializers
from django.core.serializers import serialize
from django.core.servers.basehttp import FileWrapper
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer, XMLRenderer
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, AllowAny
from itertools import chain
from TAPI.renderers import *
from TAPI.models import *
from TAPI.serializers import JobdtlSerializer, JobmstSerializer, TrgjobSerializer, JobdepSerializer
class TESTXMLDetail(APIView):
permission_classes = (AllowAny,)
"""
Retrieve, update or delete a snippet instance.
"""
def get_object(self, pk):
try:
mst = Jobmst.objects.db_manager('AdmiralDEV').raw("""
query1""", [pk])
dtl = Jobdtl.objects.db_manager('AdmiralDEV').raw("""
query2""", [pk])
dep = Jobdep.objects.db_manager('AdmiralDEV').raw("""
query3""", [pk])
trg = Trgjob.objects.db_manager('AdmiralDEV').raw("""
query4""", [pk])
except Jobmst.DoesNotExist:
return HttpResponse(status=404)
def get(self, request, pk, format=None):
jobmststring = JobmstSerializer(mst)
jobdtlstring = JobdtlSerializer(dtl)
jobdepstring = JobdepSerializer(dep, many=True)
trgjobstring = TrgjobSerializer(trg, many=True)
jobmst_serialized = {'jobmst': jobmststring.data}
jobdtl_serialized = {'jobdtl': jobdtlstring.data}
jobdep_serialized = [{'jobdep':item} for item in jobdepstring.data]
trgjob_serialized = [{'trgjob':item} for item in trgjobstring.data]
jobgroup = jobmst_serialized, jobdtl_serialized, jobdep_serialized, trgjob_serialized
jobgroupresponse = TESXMLResponse(jobgroup)
return jobgroupresponse
When I run the URL all I get is the XML format but then it says -
<detail>Method 'GET' not allowed.</detail>
I've tried setting the permission class in the view as above and I've also put the following lines in my settings.py what gives?
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),

You're getting this error because the DRF APIView doesn't have a get method (or a method for any HTTP request type actually).To get your code working you can either rename your get_object method to get (making sure you add the expected parameters request and format), or you can write a get method to return your response:
class TESTXMLDetail(APIView):
def get(self, request, pk, format=None):
return self.get_object(pk)
def get_object(self, pk):
...
...

Related

Shopify webhook request verification for `orders/create` topic returning False in python/django project [duplicate]

How can I verify the incoming webhook from Shopify? Shopify provides a python implementation (of Flask), but how can I do it in Django/DRF?
Set these two variables in the settings.py file
# settings.py
SHOPIFY_HMAC_HEADER = "HTTP_X_SHOPIFY_HMAC_SHA256"
SHOPIFY_API_SECRET = "5f6b6_my_secret"
Then, create a verify webhook function that accepts the Django request as it's parameter
# utils.py
import base64
import hashlib
import hmac
from django.conf import settings
from django.core.handlers.wsgi import WSGIRequest
def verify_shopify_webhook(request: WSGIRequest):
shopify_hmac_header = request.META.get(settings.SHOPIFY_HMAC_HEADER)
encoded_secret = settings.SHOPIFY_API_SECRET.encode("utf-8")
digest = hmac.new(
encoded_secret,
request.body,
digestmod=hashlib.sha256,
).digest()
computed_hmac = base64.b64encode(digest)
return hmac.compare_digest(computed_hmac, shopify_hmac_header.encode("utf-8"))
Then, create a view that accepts the incoming webhook and use the verify_shopify_webhook(...) function to verify the request.
# views.py
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from .utils import verify_shopify_webhook
#method_decorator(csrf_exempt, name="dispatch")
class ShopifyWebhookView(View):
def post(self, request, *args, **kwargs):
verified = verify_shopify_webhook(request=request)
return HttpResponse(status=200 if verified else 403)
If you're using Django REST Framework, you can also use APIView as
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .utils import verify_shopify_webhook
class ShopifyWebhookView(APIView):
def post(self, request, *args, **kwargs):
verified = verify_shopify_webhook(request=request)
return Response(status=200 if verified else 403)

Specifying view function in Django

I'm practicing in Django and I want to know how requests and view mechanisms work correct in Django.
I started an app called ghcrawler in my django project. I designed like it has to send responses that recevied from localhost/ghcrawler and localhost/ghcrawler/results
So this is the urls.py in ghcrawler/ app folder.
from django.urls import path, include
from .views import main_view, results_view
urlpatterns = [
path('', main_view.as_view() , name='ghcrawler'),
path('ghresults', results_view.as_view(), name='getresults')
]
localhost/grcrawler page works well as expected. I just want to wire the requests coming to localhost/ghcrawler/results to getresults() function in results_view class defined in views.py, however it doesn't even write the 'h1' to the console
ghcrawler/views.py:
from django.views.generic import TemplateView
from django.shortcuts import render
from django import forms
from django.http import HttpResponse
from .github_requester import search_user
class main_view(TemplateView):
template_name = 'ghcrawler.html'
# Handle the post request received from /ghcrawler/
def post(self, request, *args, **kwargs):
if request.method == 'POST':
user = search_user(request.POST.get("username", ""))
if user == None:
print("User not found.")
else:
print(user)
return HttpResponse("OK")
class results_view(TemplateView):
template_name = 'ghresults.html'
def getresults(self, request, *args, **kwargs):
print('h1')
Rather than localhost/ghcrawler/results you mapped localhost/ghcrawler/ghresults to your view.
the rigth code would be:
urlpatterns = [
path('', main_view.as_view() , name='ghcrawler'),
path('results', results_view.as_view(), name='ghresults')
]
the firs argument in pathis the actual path
the secont argumen is the view
the third argument name is optional and used for addressing your view independant of your path
class results_view(TemplateView):
template_name = 'ghresults.html'
def get(self, request, *args, **kwargs):
print('h1')

Django rest framework error while uploading image, submitted data is not file

I am new to Django rest framework and when ever I try to do post request via Postman and python script itself it shows error
{'bloodbank_logo': ['The submitted data was not a file. Check the encoding type on the form.']}
But there is no error when I try to post image using django admin.
my models.py
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
# Create your models here.
class Bloodbanks(models.Model):
bloodbank_user=models.ForeignKey(User, on_delete=models.CASCADE)
fullbankname=models.CharField(max_length=80,blank=False,default='Null')
apositive=models.PositiveIntegerField()
anegative=models.PositiveIntegerField()
bpositive=models.PositiveIntegerField()
bnegative=models.PositiveIntegerField()
abpositive=models.PositiveIntegerField()
abnegative=models.PositiveIntegerField()
opositive=models.PositiveIntegerField()
onegative=models.PositiveIntegerField()
latitude=models.CharField(max_length=20,blank=False,default='Null')
longitude=models.CharField(max_length=20,blank=False,default='Null')
state = models.CharField(max_length=100)
district=models.CharField(max_length=20,blank=False,default='Null')
location=models.CharField(max_length=20,blank=False,default='Null')
website = models.CharField(max_length=100, blank=True)
bloodbank_logo=models.ImageField(blank=False)
bloodbank_description=models.CharField(blank=True,max_length=200)
bloodbank_phone=models.CharField(blank=True,max_length=10)
def __str__(self):
return self.fullbankname
my serializers.py
from rest_framework import serializers,reverse
from bloodbank_api.models import Bloodbanks
class BloodbankdataSerializer(serializers.ModelSerializer):
bloodbanks_user=serializers.PrimaryKeyRelatedField(source='user.username',read_only=True)
url = serializers.HyperlinkedIdentityField(
view_name='bloodbank-detail-id',
lookup_field='pk'
)
bloodbank_logo=serializers.ImageField
class Meta:
model=Bloodbanks
fields=['id','bloodbanks_user','fullbankname','apositive',
'anegative','bpositive','bnegative','abpositive',
'abnegative','opositive','onegative','latitude',
'longitude','state','district','location','website',
'bloodbank_logo','bloodbank_description','bloodbank_phone','url']
views.py
from bloodbank_api.models import Bloodbanks
from bloodbank_api.serializers import BloodbankdataSerializer
from rest_framework import status,mixins,generics
from rest_framework.parsers import FormParser, MultiPartParser,JSONParser
from rest_framework.response import Response
from django.contrib.auth.models import User
# Create your views here
#updatelistpostput by primary key
class BloodbankDataDetail(mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
queryset = Bloodbanks.objects.all()
serializer_class = BloodbankdataSerializer
parser_class=(MultiPartParser,JSONParser, FormParser)
lookup_field = 'pk'
def get(self, request,*args, **kwargs):
id=kwargs.get('pk')
if id is not None:
return self.retrieve(request,*args, **kwargs)
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
print(args,kwargs)
return self.create(request, *args, **kwargs)
def perform_create(self, serializer):
serializer.save(bloodbank_user=self.request.user)
urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from bloodbank_api.views import BloodbankDataDetail
from django.conf import settings
from django.conf.urls.static import static
urlpatterns=[
path('bloodbank/',BloodbankDataDetail.as_view(),name='bloodbank-detail'),
path('bloodbank/<int:pk>/',BloodbankDataDetail.as_view(),name='bloodbank-detail-id'),
]
urlpatterns = format_suffix_patterns(urlpatterns)+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
the python script that i have used to post do post request
import requests
endpoint='http://127.0.0.1:8000/bloodbank/'
data={
"fullbankname": "Dirgahyu",
"apositive": '1',
"anegative": '1',
"bpositive": '1',
"bnegative": '1',
"abpositive": '1',
"abnegative": '1',
"opositive": '1',
"onegative": '1',
"latitude": "dhdhd",
"longitude": "hdhdd",
"state": "dhhd",
"district": "dhdhgd",
"location": "dhdhdhd",
"website": "jdjdjd",
"bloodbank_logo": "/Users/aayushdipgiri/aayu's code/opencv/cat.jpeg",
"bloodbank_description": "hahaha",
"bloodbank_phone": "hhdhddh"
}
get_response = requests.post(endpoint, json=data)
print(get_response.json())
First thing I notice is that you are not sending an image, you are sending a string. Try this instead to send the file via requests module.
"bloodbank_logo": open("/Users/aayushdipgiri/aayu's code/opencv/cat.jpeg", "rb"),
If this does not work, I would try using django's FileField instead, but I won't go into detail as the above should work or give you a different error message at least.

“detail”: “Method \”GET\“ not allowed.” Django Rest Framework

I know this question was duplicate I am beginner in django I tried in all ways but not able to find solution
I was trying to upload a file and get a json response as ok using django rest framework
So far I tried is
views.py:
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework import status
from .serializers import FileSerializer
class FileView(APIView):
parser_classes = (MultiPartParser, FormParser)
def post(self, request, *args, **kwargs):
file_serializer = FileSerializer(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
urls.py:
from django.conf.urls import url
from .views import FileView
urlpatterns = [
url(r'^upload/$', FileView.as_view(), name='file-upload'),
url(r'^upload/<int:pk>/$', FileView.as_view(), name='file-upload'),
]
The error is:
Method /GET/ is not allowed
please help me thanks in advance
If you can have a look at your view.py file, You don't have any GET method and this is why it is not able to call the URL with GET request.

How can I pass in url arguments to an APIRequestFactory put request?

I have been trying for hours but cannot figure out how to pass a url argument through an APIRequestFactory put request. I have tried it through Postman when running my server and the url variable is passed just fine, but when I run it in my tests it stops working.
What I mean is that when I send a Postman PUT request to '/litter/1/' it will successfully take in the 1 as the variable litterId since my url is setup like this
path('litter/', include('apps.litter.urls')),
and
path('<int:litterId>/', LitterView.as_view(), name='litter-with-id')
But when I try and send an APIRequestFactory put request to that same url, for some reason the 1 will not go through as the litterId anymore.
Some relevant pieces of code...
My top level url.py
from rest_framework.authtoken import views
from apps.litter.views import LitterView
urlpatterns = [
path('admin/', admin.site.urls),
path('auth/', include('apps.my_auth.urls')),
path('litter/', include('apps.litter.urls')),
]
This is my app specific urls.py
from .views import LitterView
urlpatterns = [
path('', LitterView.as_view(), name='standard-litter'),
path('<int:litterId>/', LitterView.as_view(), name='litter-with-id'),
]
Here is my views.py
import json
from django.contrib.auth.models import User
from django.db import IntegrityError
from django.views.decorators.csrf import csrf_exempt
from rest_framework import authentication, permissions
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from django.db import models
from .models import Litter
from .serializers import LitterSerializer
##csrf_exempt
class LitterView(APIView):
"""
View for litter related requests
* Requres token auth
"""
permission_classes = (IsAuthenticated,)
authentication_classes = [authentication.TokenAuthentication]
renderer_classes = [JSONRenderer]
def put(self, request, litterId=0):
"""
Updates an old litter
"""
try:
litterModel = Litter.objects.get(user=request.user, id=litterId)
except Litter.DoesNotExist:
returnData = {'status': 'fail',
'error': 'Could not find object with that id.'}
return Response(returnData)
serializer_class = LitterSerializer
serialized = LitterSerializer(litterModel, data=request.data)
if serialized.is_valid():
litterModel = serialized.save()
returnData = {'status': 'okay',
'litter': [serialized.data]}
return Response(returnData)
else:
return Response(serialized.errors, status=400)
And here is the relevant test.
def test_easy_successful_put_type(self):
"""
Testing a simple put
"""
user = UserFactory()
amount = 40
amountChange = 20
litter = LitterFactory(user=user, amount=amount)
data = {'typeOfLitter': litter.typeOfLitter,
'amount': litter.amount + amountChange,
'timeCollected': litter.timeCollected}
url = '/litter/' + str(litter.id) + '/'
request = self.factory.put(url, data, format='json')
force_authenticate(request, user=user)
view = LitterView.as_view()
response = view(request).render()
responseData = json.loads(response.content)
No matter what I do, I cannot get the int:litterId to get passed in, the put function always has the default value of 0. Any help would be greatly appreciated.
Your problem is here:
response = view(request).render()
You are manually passing the request to the view, also not passing the kwarg litterId, instead use APIClient and make a put request to the url. First import the required modules:
from django.urls import reverse
from rest_framework.test import APIClient
then:
user = UserFactory()
amount = 40
amountChange = 20
litter = LitterFactory(user=user, amount=amount)
data = {
'typeOfLitter': litter.typeOfLitter,
'amount': litter.amount + amountChange,
'timeCollected': litter.timeCollected
}
url = reverse('litter-with-id', kwargs={'litterId': litter.id})
client = APIClient()
client.force_authenticate(user=user)
response = client.put(url, data, format='json')

Categories