I'm trying to use custom permissions in my class based views.
When I try to run one of my views, I get a WrappedAttributeError : 'UserViewPermissionClass' object has no attribute 'authenticate'
Here are my custom permissions :
class UserViewPermissionClass(BasePermission):
def has_permission(self, request, view):
if request.method == 'GET':
return request.user.is_admin
elif request.method == 'POST':
return True
# default logic
class UserView(APIView):
authentication_classes = ( UserViewPermissionClass,)
This is the class based view that I'm trying to run :
class HandleUsers(UserView):
def get(self, request):
"""Only for admin"""
try:
users = User.objects.all()
except User.DoesNotExist():
return HttpResponse(status=404)
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
def post(self, request):
"""For everyone"""
serializer = RegistrationSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.error)
Here are my settings for rest framework :
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
}
After doing some research I saw that my error could be due to my DEFAULT_PERMISSION_CLASSES. However I cannot see what could be blocking.
Thank you in advance for your help.
change authentication_classes=(UserViewPermissionClass,) to permission_classes=(UserViewPermissionClass,)
Related
can anyone help please, with DRF
according to POST request, I want to create(if not exists) or update() table
belows are my codes
model.py
class User1(models.Model):
user = models.CharField(max_length=10)
full_name = models.CharField(max_length=20)
logon_data = models.DateTimeField(blank=True, null=True)
serializer.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User1
fields = '__all__'
views.py
from .models import User1
from .serializers import UserSerializer
from rest_framework.response import Response
from rest_framework.decorators import api_view
#api_view(['GET', 'POST'])
def UserView(request):
if request.method == 'GET':
users = User1.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
elif request.method == 'POST':
users = User1.objects.all()
serializer = UserSerializer(data=request.data, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('users/', views.UserView),
]
when POST request, I want to check like this:
if user exists:
if user.full_name == request.fullname
update (user.logon_data)
save()
else:
update (user.full_name)
update (user.logon_data)
save()
else:
create(
user = request.user,
full_name = request.full_name,
logon_data = request.logon_date)
save()
POST request for JSON like this:
[
{
"user": "testuser1",
"full_name": "test user1",
"logon_data": "2022-10-19 09:37:26"
},
{
"user": "testuser2",
"full_name": "test user2",
"logon_data": "2022-10-20 07:02:06"
}
]
#api_view(['GET', 'POST'])
def UserView(request):
if request.method == 'GET':
users = User1.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = UserSerializer(data=request.data, many=True)
# if serializer validation fails, raises error by itself
serializer.is_valid(raise_exception=True)
for data in serializer.validated_data:
# checking if data exists else creating an object in User1 model
# user = data['user'] --> filter to check if that user exist
# defaults={'full_name': data['full_name'], 'logon_data': #data['logon_data']} --> value provided in defaults is used to update data in #model once the condition is met.
User1.objects.update_or_create(user=data['user'], defaults={'full_name': data['full_name'], 'logon_data': data['logon_data']})
return Response(serializer.data, status=201)
Try this update_or_create it will check based on request.user whether it exists in table or not
Also ensure that request.user is checked to user object if you want to check specific field then it should be request.user.user
User.objects.update_or_create(user=request.user.user, defaults={"full_name": request.full_name, "logon_date":request.logon_date})
I have POST method in views.py in django to create an entry in database
I can create a single entry using postman, but can not create bulk entries using postman
can anyone help, please?
models.py file
from django.db import models
class Users(models.Model):
user = models.CharField(max_length=50,default='')
function = models.CharField(max_length=50,default='')
department = models.CharField(max_length=50,default='')
logon = models.CharField(max_length=50,default='')
def __str__(self):
return self.user+" - Last_Logon: "+self.logon
class Meta:
ordering = ('id',)
serializers.py file
from rest_framework import serializers
from activities.models import Users
class UsersSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = ('id', 'user', 'function', 'department', 'logon')
views.py file with GET,POST,PUT,DELETE, from this file POST method creates only a single entry
from django.shortcuts import render
from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from rest_framework import status
from activities.models import Users
from activities.serializers import UsersSerializer
from rest_framework.decorators import api_view
#api_view(['GET', 'POST'])
def users_list(request):
if request.method == 'GET':
users = Users.objects.all()
user = request.GET.get('user', None)
if user is not None:
users = users.filter(user__icontains=user)
users_serializer = UsersSerializer(users, many=True)
return JsonResponse(users_serializer.data, safe=False)
# 'safe=False' for objects serialization
elif request.method == 'POST':
users_data = JSONParser().parse(request)
users_serializer = UsersSerializer(data=users_data)
if users_serializer.is_valid():
users_serializer.save()
return JsonResponse(users_serializer.data, status=status.HTTP_201_CREATED)
return JsonResponse(users_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#api_view(['GET', 'PUT', 'DELETE'])
def users_detail(request, pk):
try:
users = Users.objects.get(pk=pk)
except Users.DoesNotExist:
return JsonResponse({'message': 'The user does not exist'}, status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
users_serializer = UsersSerializer(users)
return JsonResponse(users_serializer.data)
elif request.method == 'PUT':
users_data = JSONParser().parse(request)
users_serializer = UsersSerializer(users, data=users_data)
if users_serializer.is_valid():
users_serializer.save()
return JsonResponse(users_serializer.data)
return JsonResponse(users_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
users.delete()
return JsonResponse({'message': 'User was deleted successfully!'}, status=status.HTTP_204_NO_CONTENT)
urls.py file
from django.urls import re_path
from activities import views
urlpatterns = [
re_path(r'^api/activities$', views.users_list),
re_path(r'^api/activities/(?P<pk>[0-9]+)$', views.users_detail),
]
if I set many=True in user serializer, UsersSerializer(data=users_data, many=True) for POST metho
In postman, for sending a single entry, got this error
for sending multiple entries, got this error
for UsersSerializer(data=users_data, many=True) you must send list of json objects
[
{
"User": "user1",
"function": "t",
"deportment": "t",
"logon": "23...."
},
{
"User": "user1",
"function": "t",
"deportment": "t",
"logon": "23...."
}
]
and for a user UsersSerializer(data=users_data)
you can split serializers with a send a query param into your url and in view function
if request.GET.get('bulk'):
serializer = UsersSerializer(data=users_data, many=True)
else:
serializer = UsersSerializer(data=users_data)
I have a API view in place where I first want to create a new user (already working) and second I want to return the new created user object using my UserSerializer (Not working).
views.py
#api_view(['POST'])
#permission_classes([AllowAny])
def user_create(request):
exception_handler = UserUnavailable
success_handler = UserCreated
if request.method == 'POST':
creation_serializer = CreateUserSerializer(data=request.data)
try:
if creation_serializer.is_valid(raise_exception=True):
creation_serializer.save()
user_serializer = UserSerializer(data=creation_serializer.instance.id)
if user_serializer.is_valid():
return JsonResponse({"status_code": success_handler.status_code,
"default_detail": success_handler.default_detail,
"default_code": success_handler.default_code,
"new_user": user_serializer,
}, safe=False)
except APIException:
return JsonResponse({"status_code": exception_handler.status_code,
"default_detail": exception_handler.default_detail,
"default_code": exception_handler.default_code
}, safe=False)
I can confirm that creation_serializer.instance.id contains the new users id.
serializers.py
class UserSerializer(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = get_user_model()
fields = ('id', 'user')
read_only_fields = ('id', 'user')
I can also confirm that
if user_serializer.is_valid()
does not validate for some reason. Any ideas
Thanks in advance
To initialize a serializer with user instance instead of
user_serializer = UserSerializer(data=creation_serializer.instance.id)
You should write something like this:
user_serializer = UserSerializer(instance=creation_serializer.instance)
instead of
Also, you don't have to validate the object that has already been saved.
And create a response you should like this:
return JsonResponse({
"status_code": success_handler.status_code,
"default_detail": success_handler.default_detail,
"default_code": success_handler.default_code,
"new_user": user_serializer.data,
}, safe=False)
But using api_view is now a bad thing. It's much better to use ModelViewSet. You can use something like this:
class UserViewSet(ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
def get_serializer_class(self, *args, **kwargs):
if self.action == 'create':
return CreateUserSerializer
return super().get_serializer_class(*args, **kwargs)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
response_serializer = self.serializer_class(instance=serializer.instance)
return Response(response_serializer.data, status=status.HTTP_201_CREATED, headers=headers)
And I'm sorry, I haven't tested it, there might be typos.
You can read about ModelViewsets more here https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset
In creating Django REST framework, i'll get all the data using this code
views.py
#api_view(['GET', ])
def api_detail_educationlevel(request):
if request.method == 'GET':
educationlevel = EducationLevel.objects.all()
serializer = EducationLevelSerializer(educationlevel, many=True)
return Response(serializer.data)
urls.py
path('api/', views.api_detail_educationlevel),
but when i add in my views.py like this
#api_view(['PUT', ])
def api_update_educationlevel(request, pk):
try:
educationlevel = EducationLevel.objects.get(pk=pk)
except EducationLevel.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'PUT':
serializer = EducationLevelSerializer(educationlevel, data=request.data)
data = {}
if serializer.is_valid():
serializer.save()
data["success"] = "update successfull"
return Response(data=data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#api_view(['DELETE', ])
def api_delete_educationlevel(request, pk):
try:
educationlevel = EducationLevel.objects.get(pk=pk)
except EducationLevel.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'DELETE':
operation = educationlevel.delete()
data ={}
if operation:
data["success"] = "delete successfull"
else:
data["failure"] = "delete failed"
return Response(data=data)
#api_view(['POST', ])
def api_create_blog_view(request):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'user': unicode(request.user), # `django.contrib.auth.User` instance.
'auth': unicode(request.auth), # None
}
return Response(content)
and in my urls.py
urlpatterns = [
path('api/', views.api_detail_educationlevel),
path('api/update/', views.api_update_educationlevel),
path('api/delete/', views.api_delete_educationlevel),
path('api/create/', views.api_create_blog_view),
]
urlpatterns = format_suffix_patterns(urlpatterns)
I dont know why i am getting this message,
in my path('api/update/', views.api_update_educationlevel),
in my path('api/delete/', views.api_delete_educationlevel),
in my path('api/create/', views.api_create_blog_view),
any idea why i am getting this message? i just want functional rest framework that can update/delete/insert data using user auth account
For each of these views (views.api_detail_educationlevel, views.api_update_educationlevel, views.api_delete_educationlevel, views.api_create_blog_view), you define #api_view(['*api method*', ]).
Only the views.api_detail_educationlevel has #api_view(['GET', ]) therefore allowing a GET method. The others don't. Either add a GET method to the other views or, like the documentation you follow, create a class containing each method.
I'm struggling to figure out how to implement the Hyperlinked relationships for non-model querysets. I have a viewset:
class GGGViewSet(viewsets.ViewSet):
def list(self, request):
serializer_class = manufacture_serializer(ar)
serializer = serializer_class(
instance = sample.values(), many=True
)
return Response(serializer.data)
def retrieve(self, request, pk=None):
try:
anobject = sample[pk]
except KeyError:
return Response(status=status.HTTP_404_NOT_FOUND)
except ValueError:
return Response(status=status.HTTP_400_BAD_REQUEST)
serializer_class = manufacture_serializer(ar)
serializer = serializer_class(instance=anobject)
return Response(serializer.data)
I am trying to get the value resource at /data/trait/ to be rendered as a link, where:
trait-list
data/trait/
{
"value": 12334,
"another_value": 45672,
}
trait-detail
data/trait/value/
{
"value":12334
}
Attempted:
url = serializers.HyperlinkedIdentityField(view_name='trait-list')
Error: AttributeError at /asvo/data/trait/ 'AObj' object has no attribute 'pk'.
Any ideas on the best way to approach this would be appreciated. :)
You were probably quite close. Based on the information provided, here's something that demonstrates HyperlinkedIdentityField usage without relying on an actual Django model. I had to use my imagination when filling in the details of your architecture.
from rest_framework import routers
from rest_framework import serializers
from rest_framework import status
from rest_framework import viewsets
from rest_framework.response import Response
# This goes in the URL routing file
router = routers.DefaultRouter()
router.register(r'trait', GGGViewSet, base_name='trait')
urlpatterns = router.urls
# The "model"
class Thing(object):
def __init__(self, pk, value, another_value):
self.pk = pk
self.value = value
self.another_value = another_value
# The "queryset"
sample = {
'1': Thing(1, 12334, 45672),
'2': Thing(2, 12335, 45673),
'3': Thing(3, 12336, 45674)
}
# The serializer
class manufacture_serializer(serializers.Serializer):
pk = serializers.HyperlinkedIdentityField(
view_name='trait-detail', read_only=True)
value = serializers.IntegerField()
another_value = serializers.IntegerField()
class Meta:
fields = ['pk', 'value', 'another_value']
# The view
class GGGViewSet(viewsets.ViewSet):
def list(self, request):
serializer = manufacture_serializer(
instance=sample.values(), many=True, context={'request': request})
return Response(serializer.data)
def retrieve(self, request, pk=None):
try:
anobject = sample[pk]
except KeyError:
return Response(status=status.HTTP_404_NOT_FOUND)
except ValueError:
return Response(status=status.HTTP_400_BAD_REQUEST)
serializer = manufacture_serializer(
instance=anobject, context={'request': request})
return Response(serializer.data)
I did not fully understand the second half of the question regarding the data/trait/ and data/trait/value/, but hopefully this is enough to further you along.
Cheers!