I have a problem with (I think) permissions. When I try to send post request via postman, I get following error:
AssertionError: Cannot apply DjangoModelPermissionsOrAnonReadOnly on a view that does not set .queryset or have a .get_queryset() method.
[29/Nov/2021 20:21:21] "POST /api/blog/category HTTP/1.1" 500 101581
Here are my views.py and category class. Also, I noticed that for some reason in def post(self, request, format=None) request is not being called ("request" is not accessed Pylance). I think the problem is somewhere here, but can't figure it out. Thank you in advance.
class BlogPostCategoryView(APIView):
serializer_class = BlogPostSerializer
permissions_classes = (permissions.AllowAny, )
def post(self, request, format=None):
data = self.request.data
category = data['category']
queryset = BlogPost.objects.order_by('-date_created').filter(category__iexact=category)
serializer = BlogPostSerializer(queryset, many=True)
return Response(serializer.data)
In settings.py you can add:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
]
}
Then in postman go to the Authorization tab and for type select Basic Auth.
You can then enter your username and password. You should be able to make Post requests after this.
Related
I have this code of 2 views in Django. You will notice that each REST API call has a verify_login() function call that ensures that the request contains a verified JWT token. I'm wondering if there's a better way to implement this so that I don't have to have these lines specifically in every REST endpoint
verify_response = verify_login(request)
if verify_response not None:
return verify_response
I'm trying to follow the D.R.Y. (Do Not Repeat Yourself) principle of coding. It'd be nice if there was a cleaner way to represent this. I thought about maybe creating a module extending APIView that automatically has this and then all my Views extend that, but runs into the issue of having to call super().API_REQUEST() and then having to do the same if-statement check to see if it's None or not.
class PostView(APIView):
"""
View for Post object
* requires token authentication
"""
# Create post
#swagger_auto_schema(
request_body=PostSerializer,
operation_description="Create a post object"
)
def post(self, request):
verify_response = verify_login(request)
if verify_response not None:
return verify_response
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# get all posts
#swagger_auto_schema(
operation_description="Get all posts from the DB"
)
def get(self, request):
verify_response = verify_login(request)
if verify_response not None:
return verify_response
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
You can use authentication classes alongside permission classes. If you want the authentication check to happen for all the APIs of your application, put your classes in settings.REST_FRAMEWORK. If you want it for specific APIView's, put them in permission_classes & authentication_classes class variables. Check out the doc for more details.
Example,
class JWTAuthenticataion(BaseAuthentication):
def authenticate(self, request):
... # write your JWT implementation here
# settings.py:
REST_FRAMEWORK = {
...
"DEFAULT_AUTHENTICATION_CLASSES": (
"path.to.JWTAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": (
"rest_framework.permissions.IsAuthenticated",
)
}
# or
# api.py
class YourAPIView(APIView):
permission_classes = (IsAuthenticated, )
authentication_classes = (JWTAuthentication, )
...
Ok, Here's the problem: I have created a POST API in Django REST framework & I want to add logged-in user to request.data when making POST request & It works perfectly fine when I create post calling this API from Postman, but when I visit the post create API endpoint from browser it throws AssertionError: '''When a serializer is passed a data keyword argument you must call .is_valid() before attempting to access the serialized .data representation.
You should either call .is_valid() first, or access .initial_data'''.
Here's the snippet of my get_serializer method which i use to override & add user to request.data:
class PostCreateView(CreateAPIView):
serializer_class = PostSerializer
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs["context"] = self.get_serializer_context()
request_data = self.request.data.copy()
request_data["user"] = self.request.user.id
kwargs["data"] = request_data
return serializer_class(*args, **kwargs)
def post(self,request):
serializer = self.get_serializer()
serializer.is_valid(raise_exception=True)
serializer.save()
status_code = status.HTTP_201_CREATED
response = {
'success' : 'True',
'status code' : status_code,
'message': 'Post created successfully',
'post_detail': serializer.data,
}
return Response(response, status=status_code)
Update: I have changed my code in post method to pass user initially in a Post instance & then pass it in PostSerializer as: serializer = self.serializer_class(post, data=request.data) & it works on both Postman as well as browser's DRF request. But I'm curious to know why my above code with get_serializer method gave me AssertionError from browser's DRF request? but worked fine when making a POST request from Postman.
I want to push front end data (Form inputs) to the server via Ajax. For this, I created an Ajax post request but I'm very unsteady...
At my first attemps, I constantly receive errors by python
Ajax call:
//Get journey time for the stated address
jQuery.ajax({
type: 'post',
url: 'http://127.0.0.1:8000/termin/get-journey-time/',
data: {
'method': 'get_journey_time',
'mandant_id': 1,
'customer_address': customer_address,
'staff_group': staff_group_id
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("Error")
},
timeout: 120000,
});
I've created a view in Python, in which I want to do something (views.py)
class get_journey_time(generics.ListAPIView):
"""
Handle Ajax Post to calculate the journey time to customer for the selected staff group
"""
permission_classes = (AllowAny,)
def post(self, request, *args, **kwargs):
print(request)
In my url route file I have this code lines (urls.py)
urlpatterns = [
XXXXXXXXXXXXXXXXXXXXXXXXX,
path('termin/get-journey-time/', views.get_journey_time.as_view()),
XXXXXXXXXXXXXXXXXXXXXXXXX,
XXXXXXXXXXXXXXXXXXXXXXXXX,
]
I got the Error code 500:
Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from the view, but received a `<class 'NoneType'>`
Is there a mistake in my approach, did I miss anything or is it completely crap?
Define renderer classes and parser classes in settings.py.
Note: You can define many of these (based on requirements and needs) but here we only need JSON related.
As a reference, you can check my repo's this file https://github.com/hygull/p-host/blob/master/src/pmt_hostel_app/views.py. I have used function based views, just ignore the code inside it and focus on request.data and also check related HTML files.
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
)
}
In this way you will be able to access the posted data in the form of dictionary which can be obtained using request.data in views.
Finally, return Response from the post() method. By default return type of function/method is None and you are just printing the request.
Check the below mentioned links, it will help you a lot.
https://www.django-rest-framework.org/api-guide/renderers/
https://www.django-rest-framework.org/api-guide/parsers/
In client code, I mean in JavaScript code, define a success callback as well (you have just defined error callback).
Please comment, if you are stuck.
you can do it like this
from rest_framework.response import Response
from rest_framework.views import APIView
class get_journey_time(APIView):
# ListAPIView is used for read-only endpoints
#
"""
Handle Ajax Post to calculate the journey time to customer for the selected staff group
"""
permission_classes = (AllowAny,)
def post(self, request, *args, **kwargs):
# you can get the posted data by request.data
posted_data = request.data
data = {"test": "test"}
return Response(data)
you can get the posted data and use serializers. you can start learning playing with serializers from here
Example serializer code can be like this
from rest_framework import serializers
class DummySerializer(serializers.Serializer):
name = serializers.CharField()
mobile_number = serializers.CharField(required=False)
and then use it in post method of your get_journey_time class
I am trying to make a rest application to communicate with my android application but it is stopping me the validation of the password.
I use the User model by default of django and I would like to try to make the server validate the password
I found some other interesting answers but the truth is that django is not my strong point (my specialty is android) and they do not explain well how to implement them in my view
restapp/views.py
class postRegister(APIView):
def post(self,request):
data = JSONParser().parse(request)
cencripM=CriptoMovil(KEY_ENC_M)
data['username'] = cencripM.decrypt(data['username'])
data['email'] = cencripM.decrypt(data['email'])
data['password'] = cencripM.decrypt(data['password'])
serializer = RegistSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response({"message":"save","state":"1"})
return Response({"message":serializer.errors,"state":"2"})
maybe it helps some of the articles that I found but I did not understand how to implement them in the view (I repeat my specialty is android)
many options but I did not know how to implement
interesting but I did not understand how to implement the view
As beginning you don't need to write your customer serializer for validation instead you can follow token base authentication to validate in android as below:
urls.py
from rest_framework.authtoken.views import ObtainAuthToken
urlpatterns +=[
url(r'^api-token-auth/', ObtainAuthToken.as_view(), name='get_auth_token')
]
Now you can post username and password at /api-token-auth/ and if it is valid you will get a token in response and response status will be 200 OK
if you need to customise response then you need to override post method of
ObtainAuthToken as below:
class CustomAuthentication(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, context={'request': request}) # this will use DRF's AuthTokenSerializer and pass your request to it
serializer.is_valid(raise_exception=True) # validate serializer
user = serializer.validated_data['user'] # you will get user instance if it is valid
token, created = Token.objects.get_or_create(user=user) # gives you token for user
response_data = {'token': token.key} # create dict with token key
# you can add any other JSON serializable details you want to add in this dict like username or related role/email
return Response(response_data)
Now in urls.py instead of using ObtainAuthToken.as_view() you need to use
CustomAuthentication.as_view() and
For other setup detail read this thread
I get stuck on making a simple RESTful test using django-rest-framework. I am new beginner to this. Please help. Thanks in advance!
version:
django >= 1.9
djangorestframework 3.3.3
python 3.4.3
POST request from terminal
curl -H "Content-Type: application/json" -X POST -d '{"title":"xyz","desc":"xyz"}' http://localhost:3000/api/test/
django's settings.py
INSTALLED_APP = {
'app',
'rest_framework',
#....skip to keep it short
}
# did not set anything
<!-- language-all: lang-python -->
REST_FRAMEWORK = {
}
# models.py
class Test(object):
def __init__(self, title, desc):
self.title = title
self.desc = desc
serializers.py
from rest_framework import serializers
class TestSerializer(serializers.Serializer):
title = serializers.CharField()
desc = serializers.CharField(max_length=200)
class Meta:
model = Test
fields = ('title', 'desc')
views.py
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
#csrf_exempt
class TestView(APIView):
def get(self, request, format=None):
# 1. we use NoSQL, is the following line still work?
# testItems = Test.objects.all()
serializer = SnippetSerializer(testItems, many=True)
return Response(serializer.data)
def post(self, request, format=None):
# 2. Unable to get any json string in request object or request.data at all!
# 3. The entire json seems disappear and get dropped
serializer = TestSerializer(data=request.data)
if serializer.is_valid():
# 4. can save() be overrided and do custom implementation? How?
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
urls.py
from django.conf.urls import patterns, url
urlpatterns = patterns(
'app',
url(r'^api/business/$', app.views.TestView.as_view()),
)
My Questions:
we use NoSQL, is the following line still work?
testItems = Test.objects.all()
empty request.data in POST JSON request.
Unable to get any json string in request object
or request.data at all! The entire json seems disappear and get
dropped. Tried to use Fiddler/Postman capture and ensure JSON did sent out
Can save() be overrided and do custom implementation? How?
I don't know about NOSQL but you can test it on shell. I'm guessing probably it works.
About request.data error; request.data is only used for file upload with django rest framework. When you post a json, it's in the body of the request. What you should do is something like this in your view:
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
import json
#csrf_exempt
class TestView(APIView):
# your get request here.
def post(self, request, format=None):
body_unicode = request.body.decode('utf-8')
data = json.loads(body_unicode)
# Now, your json content is stores in data as a dictionary.
serializer = TestSerializer(data=request.data)
if serializer.is_valid():
# 4. can save() be overrided and do custom implementation? How?
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
FYI,I use serializers for just creating json, I don't use it to create object. Therefore, I'm not sure if this version %100 works or not. But I'm pretty sure that 2 line I've added turns JSON to dictionary. If serializer accepts dictionary as a data, it'll work.