Django Rest-Framework-Simplejwt not working with modheader - django

I am working on some projects and trying to the list view of the book. I used Django Rest-Framework-Simplejwt to generate tokens and mod header for authentication. When I tried to request a token for a user such as the admin user, and enter it into the mod header, the request is still unauthorized. I tried to do it a couple of times, but still not working.
Views.py
from rest_framework import generics, permissions
from rest_framework.permissions import IsAuthenticated
from rest_framework.exceptions import ValidationError
from django.contrib.auth.models import User
from .models import Book
from .serializers import (
BookSerializer,
RegistrationSerializer
)
class BookCreateView(generics.CreateAPIView):
"""Create a Book"""
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = (IsAuthenticated,)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class BookListView(generics.ListAPIView):
"""Show all books"""
serializer_class = BookSerializer
permission_classes = (IsAuthenticated,)
def get_queryset(self):
user = self.request.user
return Book.objects.filter(user=user)
class BookDetailView(generics.RetrieveAPIView):
"""Show detail of the book"""
serializer_class = BookSerializer
permission_classes = (IsAuthenticated,)
def get_queryset(self):
user = self.request.user
return Book.objects.filter(user=user)
class BookUpdateView(generics.RetrieveUpdateDestroyAPIView):
"""update detail of the book"""
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = (IsAuthenticated,)
def delete(self, request, *args, **kwargs):
book = Book.objects.filter(user=self.request.user, pk=kwargs['pk'])
if book.exists():
return self.destroy(request, *args, **kwargs)
else:
raise ValidationError('Book is not yours!')
def perform_update(self, serializer, **kwargs):
book = Book.objects.get(pk=self.kwargs['pk'])
if self.request.user != book.user:
raise ValidationError("You are not the owner of this book")
serializer.save(user=self.request.user, book=book)
class UserRegistrationView(generics.CreateAPIView):
queryset = User.objects.all()
serializer_class = RegistrationSerializer
permission_classes = [permissions.AllowAny]
Serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User
from .models import Book
class BookSerializer(serializers.ModelSerializer):
"""Serializer for Book"""
class Meta:
model = Book
fields = (
'id','user',
'title', 'author',
'description', 'image')
read_only_fields = ('id', 'user')
class RegistrationSerializer(serializers.ModelSerializer):
password = serializers.CharField(style={'input type':'password'}, write_only=True)
class Meta:
model = User
fields = ('username', 'email', 'password')
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'])
user.set_password(validated_data['password'])
user.save()
return user
I entered the correct Token (copy&paste), but still not able to authenticate.

You are using "Token <eyJ..>". But instead your token should be like "Bearer <eyJ..>"
Some of Simple JWT’s behavior can be customized through settings variables in settings.py

Related

'type' object is not iterable django-rest-framework

I am new to mobile app development and I am trying to make my first app with react-native and Django rest-framework as the backend. When I try to run the server and access any model through the django-rest-framework I get
"TypeError: 'type' object is not iterable." I have tried to look up a way to solve it but every way I found online did not help.
Here is my code:
models.py
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
class Movie(models.Model):
title = models.CharField(max_length=32)
description = models.TextField()
def no_of_ratings(self):
ratings = Rating.objects.filter(movie=self)
return len(ratings)
def avg_rating(self):
sum = 0
ratings = Rating.objects.filter(movie=self)
for rating in ratings:
sum += rating.stars
if len(ratings) > 0:
return sum / len(ratings)
else:
return 0
class Rating(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
stars = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
class Meta:
unique_together = (('user', 'movie'))
index_together = (('user', 'movie'))
serializers.py
from rest_framework import serializer
from .models import Movie, Rating
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields =('id', 'title', 'description', 'no_of_ratings', 'avg_rating')
class RatingSerializer(serializers.ModelSerializer):
class Meta:
model = Rating
fields =('id', 'stars', 'user', 'movie')
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields =('id', 'username', 'password')
extra_kwargs = {'password': {'write_only': True, 'required': True}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user)
return user
views.py
from django.shortcuts import render
from rest_framework import viewsets, status
from .serializers import MovieSerializer, RatingSerializer, UserSerializer
from .models import Movie, Rating
from rest_framework.response import Response
from rest_framework.decorators import action
from django.contrib.auth.models import User
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.permissions import IsAuthenticatedOrReadOnly, BasePermission
# Create your views here.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
authentication_classes = (TokenAuthentication)
permission_classes = (IsAuthenticated)
#action(detail=True, methods=['POST'])
def rate_movie(self, request, pk=None):
if 'stars' in request.data:
movie = Movie.objects.get(id=pk)
stars = request.data['stars']
user = request.user
try:
rating = Rating.objects.get(user=user.id, movie=movie.id)
rating.stars = stars
rating.save()
serializer = RatingSerializer(rating, mamy=False)
Rating.objects.create(user=user, movie=movie, stars=stars)
response = {'message': 'Rating Updated', 'result': serializer.data}
except:
rating = Rating.objects.create(user=user, movie=movie, stars=stars)
serializer = RatingSerializer(rating, mamy=False)
response = {'message': 'Rating created', 'result': serializer.data}
return Response(response, status=status.HTTP_200_OK)
else:
response = {'message': 'you need to provide stars'}
return Response(response, status=status.HTTP_400_BAD_REQUEST)
class RatingViewSet(viewsets.ModelViewSet):
queryset = Rating.objects.all()
serializer_class = RatingSerializer
authentication_classes = (TokenAuthentication)
permission_classes = (AllowAny)
def update(self, request, *args, **kwargs):
response = {'message': 'You cant update rating like that'}
return Response(response, status=status.HTTP_400_BAD_REQUEST)
def create(self, request, *args, **kwargs):
response = {'message': 'You cant create rating like that'}
return Response(response, status=status.HTTP_400_BAD_REQUEST)
How can I fix this error?
authentication_classes and permission_classes must be tuple or list. When you put single class in parantheses, it will not behave with it as tuple but just one, so cannot iterate over it.
Change them as below in all your viewsets (Put an extra comma after them to show python that these parantheses demonstrate tuple):
#...
authentication_classes = (TokenAuthentication,)
permission_classes = (AllowAny,)
#...

Add an Image field and audio field on the front end. Using Django backend and reactjs front end

I need to add an image field and audio field in the front end. The Audio file should be accepted from a user in the front end. Then, ml file should be given the accepted file for processing and a text and image returned from it should be shown in the front end. How can I proceed?
models.py
from django.db import models
from django.conf import settings
class Question(models.Model):
document = models.FileField(upload_to='documents/',default= "../../audio.wav")
document = models.FileField('uploads/%Y/%m/% d/')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="questions")
def __str__(self):
return self.document
class Answer(models.Model):
transcript = models.TextField(max_length=255, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
question = models.ForeignKey(Question,
on_delete=models.CASCADE,
related_name="answers")
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
voters = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name="votes")
def __str__(self):
return self.transcript
view.py
from rest_framework import generics, status, viewsets
from rest_framework.exceptions import ValidationError
from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
import speech_recognition as sr
import webbrowser as wb
from pydub import AudioSegment
from questions.api.permissions import IsAuthorOrReadOnly
from questions.api.serializers import AnswerSerializer, QuestionSerializer
from questions.models import Answer, Question
r1=sr.Recognizer()
class AnswerCreateAPIView(generics.CreateAPIView):
"""Allow users to answer a question instance if they haven't already."""
queryset = Answer.objects.all()
serializer_class = AnswerSerializer
permission_classes = [IsAuthenticated]
def perform_create(self, serializer):
request_user = self.request.user
kwarg_slug = self.kwargs.get("slug")
question = get_object_or_404(Question, slug=kwarg_slug)
if question.answers.filter(author=request_user).exists():
raise ValidationError("You have already answered this Question!")
serializer.save(author=request_user, question=question)
class AnswerLikeAPIView(APIView):
"""Allow users to add/remove a like to/from an answer instance."""
serializer_class = AnswerSerializer
permission_classes = [IsAuthenticated]
def delete(self, request, pk):
"""Remove request.user from the voters queryset of an answer instance."""
answer = get_object_or_404(Answer, pk=pk)
user = request.user
answer.voters.remove(user)
answer.save()
serializer_context = {"request": request}
serializer = self.serializer_class(answer, context=serializer_context)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request, pk):
"""Add request.user to the voters queryset of an answer instance."""
#audio_file = request.FILES.get('audio')
#shipingphoto_obj = ShipPhoto.
if request.FILES['audio']:
myfile = request.FILES['audio']
sound = AudioSegment.from_mp3(myfile)
sound.export("audio.wav", format="wav")
#half_point = len(sound)//6
with sr.AudioFile('audio.wav') as source:
audio = r1.listen(source)
print("Text"+r1.recognize_google(audio))
#fs = FileSystemStorage()
#filename = fs.save(myfile.name, myfile)
x= r1.recognize_google(audio)
#answer = get_object_or_404(Answer, pk=pk)
answer = get_object_or_404(Question, pk=pk)
user = request.user
x="Hello"
answer.transcript.add(x)
answer.voters.add(user)
answer.save()
serializer_context = {"request": request}
serializer = self.serializer_class(answer, context=serializer_context)
request.post
return Response(serializer.data, status=status.HTTP_200_OK)
class AnswerListAPIView(generics.ListAPIView):
"""Provide the answers queryset of a specific question instance."""
serializer_class = AnswerSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
kwarg_slug = self.kwargs.get("slug")
return Answer.objects.filter(question__slug=kwarg_slug).order_by("-created_at")
class AnswerRUDAPIView(generics.RetrieveUpdateDestroyAPIView):
"""Provide *RUD functionality for an answer instance to it's author."""
queryset = Answer.objects.all()
serializer_class = AnswerSerializer
permission_classes = [IsAuthenticated, IsAuthorOrReadOnly]
class QuestionViewSet(viewsets.ModelViewSet):
"""Provide CRUD +L functionality for Question."""
queryset = Question.objects.all().order_by("-created_at")
lookup_field = "slug"
serializer_class = QuestionSerializer
permission_classes = [IsAuthenticated, IsAuthorOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
Settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

No PUT method in DRF using ModelViewset

I am using Django 2.2 with Django Rest Framework 3.7.
I have a class like this:
class UserViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
serializer_class = UserSerializer
queryset = User.objects.all()
def update(self, request, *args, **kwargs):
import pdb;pdb.set_trace()
I've created UserSerializer like this:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'name', 'password')
write_only_fields = ('password',)
read_only_fields = ('id',)
def create(self, validated_data):
user = User.objects.create(
email=validated_data['email'],
name=validated_data['name'],
)
user.set_password(validated_data['password'])
user.save()
return user
def update(self, instance, validated_data):
print('lalala from serialzier')
import pdb;pdb.set_trace()
instance.username = validated_data['username']
instance.save()
return instance
Only allowed methods being shown are - Allow: GET, POST, HEAD, OPTIONS
I wonder why I am unable to perform actions like PUT, DELETE, RETRIEVE. These are by default supported by using ModelViewset as per documentation.
In shown code neither serializer's update() nor views.py update() method getting called. Any hint would be appreciated.
Does this answer your question?
class UserViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
serializer_class = UserSerializer
queryset = User.objects.all()
def put(self, request, id, format=None):
...
def delete(self, request, id, format=None):
...

Authentication for class based views in Django

class AdminView(generic.ListView):
model = get_user_model()
fields = ['first_name', 'username', 'is_active']
template_name = 'users/admin.html'
class AdminUpdateView(UpdateView):
model = get_user_model()
fields = ['is_active']
template_name = 'users/user_update.html'
success_url = reverse_lazy('users:admin')
There are two views in django which I have created and I want them to be accessed only when the admin/staff logins. How do I go about it?
You can use the UserPassesTestMixin [Django-doc] and LoginRequiredMixin [Django-doc] mixins, and specify as condition that the user should be an is_superuser. Since you need these twice, we can make first a composite mixin:
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
class AdminStaffRequiredMixin(LoginRequiredMixin, UserPassesTestMixin):
def test_func(self):
return self.request.user.is_superuser or self.request.user.is_staff
Next you can add the mixin to your class-based views:
class AdminView(AdminStaffRequiredMixin, generic.ListView):
model = get_user_model()
fields = ['first_name', 'username', 'is_active']
template_name = 'users/admin.html'
class AdminUpdateView(AdminStaffRequiredMixin, UpdateView):
model = get_user_model()
fields = ['is_active']
template_name = 'users/user_update.html'
success_url = reverse_lazy('users:admin')
You can use UserPassesTestMixin:
from django.contrib.auth.mixins import UserPassesTestMixin
class AdminView(UserPassesTestMixin, generic.ListView):
model = get_user_model()
fields = ['first_name', 'username', 'is_active']
template_name = 'users/admin.html'
def test_func(self):
return self.request.user.is_staff or self.request.user.is_superuser
Use decorators, with #login_required you can tell this views will be only accesseed when user os logged in, you can pass parameters to it too or create one your own to validate if the logged user on the request can see or no your view
With Login Required
from django.contrib.auth.decorators import login_required
#login_required(login_url='/accounts/login/')
class AdminView(generic.ListView):
...
#login_required(login_url='/accounts/login/')
class AdminUpdateView(UpdateView):
...
https://docs.djangoproject.com/en/2.0/topics/auth/default/#the-login-required-decorator
With Permission
from django.contrib.auth.decorators import permission_required
#permission_required('user.is_staff')
def my_view(request):
...
https://docs.djangoproject.com/en/2.0/topics/auth/default/#the-permission-required-decorator
If you want to use the LoginRequiredMixin, you still can. And it is much simpler. Just extend the LoginRequiredMixin in all you classes so that they are like this.
class AdminView(LoginRequiredMixin, generic.ListView):
model = get_user_model()
fields = ['first_name', 'username', 'is_active']
template_name = 'users/admin.html'
class AdminUpdateView(LoginRequiredMixin, UpdateView):
model = get_user_model()
fields = ['is_active']
template_name = 'users/user_update.html'
success_url = reverse_lazy('users:admin')
This ensures that the user is already logged in before allowing any operations. Then, check if the user is an admin by adding the following code to each of the classes;
def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_staff:
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
Your code should now look like this:
class AdminView(LoginRequiredMixin, generic.ListView):
model = get_user_model()
fields = ['first_name', 'username', 'is_active']
template_name = 'users/admin.html'
def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_staff:
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
class AdminUpdateView(LoginRequiredMixin, UpdateView):
model = get_user_model()
fields = ['is_active']
template_name = 'users/user_update.html'
success_url = reverse_lazy('users:admin')
def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_staff:
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
You can use IsAdminUser permission by rest framework
from rest_framework import permissions
class AdminView(generic.ListView):
permission_classes = (permissions.IsAdminUser, )
...

Django REST Framework full serialization for personal data

What is the proper way to let authenticated users access their own private information, while other users would only be able to access the public information ?
I tried creating 2 serializers:
from rest_framework import serializers
from app.models import User
class PublicUserSerializer(serializers.HyperlinkedModelSerializer):
image_url = serializers.ImageField(use_url=False)
class Meta:
model = User
fields = (
'pk',
'first_name',
'last_name',
'image_url',
)
lookup_field = 'pk'
extra_kwargs = {
'url': {'lookup_field': 'pk'}
}
class PrivateUserSerializer(PublicUserSerializer):
class Meta:
fields = (
'pk',
'first_name',
'last_name',
'image_url',
'details',
'email',
)
But now, I'm wondering how should I update the viewset to choose the proper serializer.
from rest_framework import viewsets
from app.authentication import FirebaseAuthentication
from app.models import User
from app.serializers import PublicUserSerializer, PrivateUserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = PublicUserSerializer
lookup_field = 'pk'
authentication_classes = (FirebaseAuthentication,)
I can override the get_serializer or get_serializer_class, but how can I access my user and check permissions within this method ?
Solution:
Serializer:
from rest_framework import serializers
from app.models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
image_url = serializers.ImageField(use_url=False)
class Meta:
model = User
fields = [
'pk',
'first_name',
'last_name',
'image_url',
'details',
]
lookup_field = 'pk'
extra_kwargs = {
'url': {'lookup_field': 'pk'}
}
class PrivateUserSerializer(UserSerializer):
class Meta(UserSerializer.Meta):
fields = UserSerializer.Meta.fields + [
'email',
]
Viewset:
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.response import Response
from app.authentication import FirebaseAuthentication
from app.models import User
from app.serializers import UserSerializer, PrivateUserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_field = 'pk'
authentication_classes = (FirebaseAuthentication,)
def retrieve(self, request, pk=None):
queryset = User.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = UserSerializer(user)
if self.request.user == user:
serializer = PrivateUserSerializer(user)
return Response(serializer.data)
I think, this would do the whole magic :)
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = PublicUserSerializer
lookup_field = 'pk'
authentication_classes = (FirebaseAuthentication,)
def get_queryset(self):
if self.request.user: # If the user authenticated
return User.objects.filter(pk=self.request.user.id)
return User.objects.all() # user not authenticated
def get_serializer_class(self):
if self.request.user: # If the user authenticated
return PrivateUserSerializer
else: # user not authenticated
return PublicUserSerializer
def list(self, request, *args, **kwargs):
if self.request.user:
private_data = PrivateUserSerializer(User.objects.filter(pk=self.request.user.id),many=True).data
public_data = PublicUserSerializer(User.objects.exclude(pk=self.request.user.id),many=True).data
return Response(data=private_data+public_data)
return Response(data=PublicUserSerializer(User.objects.all(),many=True).data)
UPDATE
The suggested answer by Fandekasp is,
def retrieve(self, request, pk=None):
queryset = User.objects.all()
user = get_object_or_404(queryset, pk=pk)
if self.request.user == user:
serializer = PrivateUserSerializer(user)
else:
serializer = PublicUserSerializer(user)
return Response(serializer.data)
You'd use Django Rest Framework's permissions
# Add this
from rest_framework.permissions import AllowAny
from rest_framework.permissions import IsAuthenticated
# Your other imports
from rest_framework import viewsets
from app.authentication import FirebaseAuthentication
from app.models import User
from app.serializers import PublicUserSerializer, PrivateUserSerializer
#permission_classes([AllowAny,])
class AllUsersViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = PublicUserSerializer
lookup_field = 'pk'
authentication_classes = (FirebaseAuthentication,)
# Apply whatever filters, permissions or logic specific for this level
#permission_classes([IsAuthenticated,])
class AuthenticatedUsersViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = PublicUserSerializer
lookup_field = 'pk'
authentication_classes = (FirebaseAuthentication,)
# Apply whatever filters, permissions or logic specific for this level
Once you have your viewsets separated, you can adjust their logic.